Commit 313c86da authored by David S. Miller's avatar David S. Miller

Merge branch 'SCTP-PMTU-discovery-fixes'

Marcelo Ricardo Leitner says:

====================
SCTP PMTU discovery fixes

This patchset fixes 2 issues with PMTU discovery that can lead to flood
of retransmissions.
The first patch fixes the issue for when PMTUD is disabled by the
application, while the second fixes it for when its enabled.

Please consider these to stable.
====================
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b707fda2 b6c5734d
...@@ -966,7 +966,7 @@ void sctp_transport_burst_limited(struct sctp_transport *); ...@@ -966,7 +966,7 @@ void sctp_transport_burst_limited(struct sctp_transport *);
void sctp_transport_burst_reset(struct sctp_transport *); void sctp_transport_burst_reset(struct sctp_transport *);
unsigned long sctp_transport_timeout(struct sctp_transport *); unsigned long sctp_transport_timeout(struct sctp_transport *);
void sctp_transport_reset(struct sctp_transport *t); void sctp_transport_reset(struct sctp_transport *t);
void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu); bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu);
void sctp_transport_immediate_rtx(struct sctp_transport *); void sctp_transport_immediate_rtx(struct sctp_transport *);
void sctp_transport_dst_release(struct sctp_transport *t); void sctp_transport_dst_release(struct sctp_transport *t);
void sctp_transport_dst_confirm(struct sctp_transport *t); void sctp_transport_dst_confirm(struct sctp_transport *t);
......
...@@ -399,20 +399,24 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, ...@@ -399,20 +399,24 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
return; return;
} }
if (t->param_flags & SPP_PMTUD_ENABLE) { if (!(t->param_flags & SPP_PMTUD_ENABLE))
/* Update transports view of the MTU */ /* We can't allow retransmitting in such case, as the
sctp_transport_update_pmtu(t, pmtu); * retransmission would be sized just as before, and thus we
* would get another icmp, and retransmit again.
*/
return;
/* Update transports view of the MTU. Return if no update was needed.
* If an update wasn't needed/possible, it also doesn't make sense to
* try to retransmit now.
*/
if (!sctp_transport_update_pmtu(t, pmtu))
return;
/* Update association pmtu. */ /* Update association pmtu. */
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
}
/* Retransmit with the new pmtu setting. /* Retransmit with the new pmtu setting. */
* Normally, if PMTU discovery is disabled, an ICMP Fragmentation
* Needed will never be sent, but if a message was sent before
* PMTU discovery was disabled that was larger than the PMTU, it
* would not be fragmented, so it must be re-transmitted fragmented.
*/
sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
} }
......
...@@ -248,28 +248,37 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) ...@@ -248,28 +248,37 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
} }
void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
{ {
struct dst_entry *dst = sctp_transport_dst_check(t); struct dst_entry *dst = sctp_transport_dst_check(t);
bool change = true;
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", pr_warn_ratelimited("%s: Reported pmtu %d too low, using default minimum of %d\n",
__func__, pmtu, SCTP_DEFAULT_MINSEGMENT); __func__, pmtu, SCTP_DEFAULT_MINSEGMENT);
/* Use default minimum segment size and disable /* Use default minimum segment instead */
* pmtu discovery on this transport. pmtu = SCTP_DEFAULT_MINSEGMENT;
*/
t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
} else {
t->pathmtu = pmtu;
} }
pmtu = SCTP_TRUNC4(pmtu);
if (dst) { if (dst) {
dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu); dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu);
dst = sctp_transport_dst_check(t); dst = sctp_transport_dst_check(t);
} }
if (!dst) if (!dst) {
t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk); t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk);
dst = t->dst;
}
if (dst) {
/* Re-fetch, as under layers may have a higher minimum size */
pmtu = SCTP_TRUNC4(dst_mtu(dst));
change = t->pathmtu != pmtu;
}
t->pathmtu = pmtu;
return change;
} }
/* Caches the dst entry and source address for a transport's destination /* Caches the dst entry and source address for a transport's destination
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment