]> git.baikalelectronics.ru Git - kernel.git/commitdiff
sctp: do state transition when PROBE_COUNT == MAX_PROBES on HB send path
authorXin Long <lucien.xin@gmail.com>
Tue, 22 Jun 2021 18:04:53 +0000 (14:04 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 22 Jun 2021 18:28:52 +0000 (11:28 -0700)
The state transition is described in rfc8899#section-5.2,
PROBE_COUNT == MAX_PROBES means the probe fails for MAX times, and the
state transition includes:

  - Base -> Error, occurs when BASE_PLPMTU Confirmation Fails,
    pl.pmtu is set to SCTP_MIN_PLPMTU,
    probe_size is still SCTP_BASE_PLPMTU;

  - Search -> Base, occurs when Black Hole Detected,
    pl.pmtu is set to SCTP_BASE_PLPMTU,
    probe_size is set back to SCTP_BASE_PLPMTU;

  - Search Complete -> Base, occurs when Black Hole Detected
    pl.pmtu is set to SCTP_BASE_PLPMTU,
    probe_size is set back to SCTP_BASE_PLPMTU;

Note a black hole is encountered when a sender is unaware that packets
are not being delivered to the destination endpoint. So it includes the
probe failures with equal probe_size to pl.pmtu, and definitely not
include that with greater probe_size than pl.pmtu. The later one is the
normal probe failure where probe_size should decrease back to pl.pmtu
and pl.probe_high is set.  pl.probe_high would be used on HB ACK recv
path in the next patch.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/structs.h
net/sctp/sm_statefuns.c
net/sctp/transport.c

index f7b056f5af37faf504823f6f89e6bfd6d5801459..31165720b28aea4af684987249725d97c474ebb8 100644 (file)
@@ -1023,6 +1023,7 @@ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu);
 void sctp_transport_immediate_rtx(struct sctp_transport *);
 void sctp_transport_dst_release(struct sctp_transport *t);
 void sctp_transport_dst_confirm(struct sctp_transport *t);
+void sctp_transport_pl_send(struct sctp_transport *t);
 
 
 /* This is the structure we use to queue packets as they come into
index 8edb9186112ab8c7ca579acd2a8adaf4c01de1c4..66c409e5b47c8c521fb6d609dc9265da196e19fb 100644 (file)
@@ -1109,6 +1109,8 @@ enum sctp_disposition sctp_sf_send_probe(struct net *net,
        if (!sctp_transport_pl_enabled(transport))
                return SCTP_DISPOSITION_CONSUME;
 
+       sctp_transport_pl_send(transport);
+
        reply = sctp_make_heartbeat(asoc, transport, transport->pl.probe_size);
        if (!reply)
                return SCTP_DISPOSITION_NOMEM;
index ca3343c2c80e1bbfd1d55b979a542d7514446231..99620d86e317e3c4c1e99aee62a35391ded96080 100644 (file)
@@ -261,6 +261,50 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
                transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
 
+void sctp_transport_pl_send(struct sctp_transport *t)
+{
+       pr_debug("%s: PLPMTUD: transport: %p, state: %d, pmtu: %d, size: %d, high: %d\n",
+                __func__, t, t->pl.state, t->pl.pmtu, t->pl.probe_size, t->pl.probe_high);
+
+       if (t->pl.probe_count < SCTP_MAX_PROBES) {
+               t->pl.probe_count++;
+               return;
+       }
+
+       if (t->pl.state == SCTP_PL_BASE) {
+               if (t->pl.probe_size == SCTP_BASE_PLPMTU) { /* BASE_PLPMTU Confirmation Failed */
+                       t->pl.state = SCTP_PL_ERROR; /* Base -> Error */
+
+                       t->pl.pmtu = SCTP_MIN_PLPMTU;
+                       t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
+                       sctp_assoc_sync_pmtu(t->asoc);
+               }
+       } else if (t->pl.state == SCTP_PL_SEARCH) {
+               if (t->pl.pmtu == t->pl.probe_size) { /* Black Hole Detected */
+                       t->pl.state = SCTP_PL_BASE;  /* Search -> Base */
+                       t->pl.probe_size = SCTP_BASE_PLPMTU;
+                       t->pl.probe_high = 0;
+
+                       t->pl.pmtu = SCTP_BASE_PLPMTU;
+                       t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
+                       sctp_assoc_sync_pmtu(t->asoc);
+               } else { /* Normal probe failure. */
+                       t->pl.probe_high = t->pl.probe_size;
+                       t->pl.probe_size = t->pl.pmtu;
+               }
+       } else if (t->pl.state == SCTP_PL_COMPLETE) {
+               if (t->pl.pmtu == t->pl.probe_size) { /* Black Hole Detected */
+                       t->pl.state = SCTP_PL_BASE;  /* Search Complete -> Base */
+                       t->pl.probe_size = SCTP_BASE_PLPMTU;
+
+                       t->pl.pmtu = SCTP_BASE_PLPMTU;
+                       t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
+                       sctp_assoc_sync_pmtu(t->asoc);
+               }
+       }
+       t->pl.probe_count = 1;
+}
+
 bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
 {
        struct dst_entry *dst = sctp_transport_dst_check(t);