Hi,
In tcp_mtudisc() we resend a TCP packet by calling tcp_output() if
the TCP maximum segment size changes. At least that is what the
code and commit message pretend.
----------------------------
revision 1.78
date: 2004/04/26 18:12:25; author: frantzen; state: Exp; lines: +10 -8;
- allow the user to force the TCP mss below the fail-safe 216 with a low
interface MTU.
- break a tcp_output() -> tcp_mtudisc() -> tcp_output() infinite recursion
when the TCP mss ends up larger than the interface MTU (when the if_mtu is
smaller than the tcp header). connections will still stall
feedback from itojun@, claudio@ and provos and testing from beck@
----------------------------
But the functions in_rtchange() and in_pcbrtentry() do not touch
t_maxseg. So orig_maxseg is always equal to tp->t_maxseg and
tcp_output() is not called after changes in t_maxseg.
The function tcp_mss() changes the maximum segment size t_maxseg,
a different value can only be detected after calling it. Note that
my diff checks whether orig_maxseg is greater than t_maxseg. For
path MTU discovery it makes only sense to resend a packet immediately
if it becomes smaller and is more likely to fit.
While tobhe@ and I were debugging the endless tcp_mtudisc() recursion
with TCP over UDP encap IPsec, we found the issue in tcp_mtudisc().
PMTU did not always work. The recursion bug is somewhere else and
the current check does not prevent it. But let's get a correct
PMTU discovery first.
ok?
bluhm
Index: netinet/tcp_subr.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.176
diff -u -p -U4 -r1.176 tcp_subr.c
--- netinet/tcp_subr.c 25 Feb 2021 02:48:21 -0000 1.176
+++ netinet/tcp_subr.c 29 Jun 2021 12:20:46 -0000
@@ -836,30 +836,30 @@ void
tcp_mtudisc(struct inpcb *inp, int errno)
{
struct tcpcb *tp = intotcpcb(inp);
struct rtentry *rt;
- int change = 0;
+ int orig_maxseg, change = 0;
if (tp == NULL)
return;
+ orig_maxseg = tp->t_maxseg;
rt = in_pcbrtentry(inp);
if (rt != NULL) {
- int orig_maxseg = tp->t_maxseg;
-
/*
* If this was not a host route, remove and realloc.
*/
if ((rt->rt_flags & RTF_HOST) == 0) {
in_rtchange(inp, errno);
if ((rt = in_pcbrtentry(inp)) == NULL)
return;
}
- if (orig_maxseg != tp->t_maxseg ||
- (rt->rt_locks & RTV_MTU))
+ if (rt->rt_locks & RTV_MTU)
change = 1;
}
tcp_mss(tp, -1);
+ if (orig_maxseg > tp->t_maxseg)
+ change = 1;
/*
* Resend unacknowledged packets
*/