TSO broken with jumbo MTU

Andre Oppermann andre at freebsd.org
Mon Oct 17 16:09:51 UTC 2011


On 17.10.2011 17:29, Ben Hutchings wrote:
> This is the fix/workaround I used:

Thanks for the fix.  I'll review it and put it into FreeBSD maybe in
a slightly different form.

-- 
Andre

> --- a/netinet/tcp_output.c
> +++ b/netinet/tcp_output.c
> @@ -1062,9 +1062,7 @@
>   	 * The TCP pseudo header checksum is always provided.
>   	 * XXX: Fixme: This is currently not the case for IPv6.
>   	 */
> -	if (tso) {
> -		KASSERT(len>  tp->t_maxopd - optlen,
> -		    ("%s: len<= tso_segsz", __func__));
> +	if (tso&&  len>  tp->t_maxopd - optlen) {
>   		m->m_pkthdr.csum_flags |= CSUM_TSO;
>   		m->m_pkthdr.tso_segsz = tp->t_maxopd - optlen;
>   	}
> --- END ---
>
> But the correct thing to do may be to change the calculation of t_maxopd
> (untested):
>
> --- a/netinet/tcp_input.c
> +++ b/netinet/tcp_input.c
> @@ -3087,7 +3087,7 @@
>   tcp_mss_update(struct tcpcb *tp, int offer,
>       struct hc_metrics_lite *metricptr, int *mtuflags)
>   {
> -	int mss;
> +	int mss, ts_len;
>   	u_long maxmtu;
>   	struct inpcb *inp = tp->t_inpcb;
>   	struct hc_metrics_lite metrics;
> @@ -3212,22 +3212,17 @@
>   	mss = max(mss, 64);
>
>   	/*
> -	 * maxopd stores the maximum length of data AND options
> -	 * in a segment; maxseg is the amount of data in a normal
> -	 * segment.  We need to store this value (maxopd) apart
> -	 * from maxseg, because now every segment carries options
> -	 * and thus we normally have somewhat less data in segments.
> -	 */
> -	tp->t_maxopd = mss;
> -
> -	/*
>   	 * origoffer==-1 indicates that no segments were received yet.
>   	 * In this case we just guess.
>   	 */
>   	if ((tp->t_flags&  (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP&&
>   	(origoffer == -1 ||
>   	     (tp->t_flags&  TF_RCVD_TSTMP) == TF_RCVD_TSTMP))
> -		mss -= TCPOLEN_TSTAMP_APPA;
> +		ts_len = TCPOLEN_TSTAMP_APPA;
> +	else
> +		ts_len = 0;
> +
> +	mss -= ts_len;
>
>   #if	(MCLBYTES&  (MCLBYTES - 1)) == 0
>   	if (mss>  MCLBYTES)
> @@ -3237,6 +3232,15 @@
>   		mss = mss / MCLBYTES * MCLBYTES;
>   #endif
>   	tp->t_maxseg = mss;
> +
> +	/*
> +	 * maxopd stores the maximum length of data AND options
> +	 * in a segment; maxseg is the amount of data in a normal
> +	 * segment.  We need to store this value (maxopd) apart
> +	 * from maxseg, because now every segment carries options
> +	 * and thus we normally have somewhat less data in segments.
> +	 */
> +	tp->t_maxopd = mss + ts_len;
>   }
>
>   void
> --- END ---
>
> Ben.
>



More information about the freebsd-net mailing list