Commit 8f61059a96c2a29c1cc5a39dfe23d06ef5b4b065

Authored by Daniel Borkmann
Committed by David S. Miller
1 parent eb1ac820c6

net: sctp: improve timer slack calculation for transport HBs

RFC4960, section 8.3 says:

  On an idle destination address that is allowed to heartbeat,
  it is recommended that a HEARTBEAT chunk is sent once per RTO
  of that destination address plus the protocol parameter
  'HB.interval', with jittering of +/- 50% of the RTO value,
  and exponential backoff of the RTO if the previous HEARTBEAT
  is unanswered.

Currently, we calculate jitter via sctp_jitter() function first,
and then add its result to the current RTO for the new timeout:

  TMO = RTO + (RAND() % RTO) - (RTO / 2)
              `------------------------^-=> sctp_jitter()

Instead, we can just simplify all this by directly calculating:

  TMO = (RTO / 2) + (RAND() % RTO)

With the help of prandom_u32_max(), we don't need to open code
our own global PRNG, but can instead just make use of the per
CPU implementation of prandom with better quality numbers. Also,
we can now spare us the conditional for divide by zero check
since no div or mod operation needs to be used. Note that
prandom_u32_max() won't emit the same result as a mod operation,
but we really don't care here as we only want to have a random
number scaled into RTO interval.

Note, exponential RTO backoff is handeled elsewhere, namely in
sctp_do_8_2_transport_strike().

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 9 additions and 29 deletions Side-by-side Diff

include/net/sctp/sctp.h
... ... @@ -388,27 +388,6 @@
388 388 return (head->next != head) && (head->next == head->prev);
389 389 }
390 390  
391   -/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */
392   -static inline __s32 sctp_jitter(__u32 rto)
393   -{
394   - static __u32 sctp_rand;
395   - __s32 ret;
396   -
397   - /* Avoid divide by zero. */
398   - if (!rto)
399   - rto = 1;
400   -
401   - sctp_rand += jiffies;
402   - sctp_rand ^= (sctp_rand << 12);
403   - sctp_rand ^= (sctp_rand >> 20);
404   -
405   - /* Choose random number from 0 to rto, then move to -50% ~ +50%
406   - * of rto.
407   - */
408   - ret = sctp_rand % rto - (rto >> 1);
409   - return ret;
410   -}
411   -
412 391 /* Break down data chunks at this point. */
413 392 static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
414 393 {
net/sctp/transport.c
... ... @@ -594,15 +594,16 @@
594 594 }
595 595  
596 596 /* What is the next timeout value for this transport? */
597   -unsigned long sctp_transport_timeout(struct sctp_transport *t)
  597 +unsigned long sctp_transport_timeout(struct sctp_transport *trans)
598 598 {
599   - unsigned long timeout;
600   - timeout = t->rto + sctp_jitter(t->rto);
601   - if ((t->state != SCTP_UNCONFIRMED) &&
602   - (t->state != SCTP_PF))
603   - timeout += t->hbinterval;
604   - timeout += jiffies;
605   - return timeout;
  599 + /* RTO + timer slack +/- 50% of RTO */
  600 + unsigned long timeout = (trans->rto >> 1) + prandom_u32_max(trans->rto);
  601 +
  602 + if (trans->state != SCTP_UNCONFIRMED &&
  603 + trans->state != SCTP_PF)
  604 + timeout += trans->hbinterval;
  605 +
  606 + return timeout + jiffies;
606 607 }
607 608  
608 609 /* Reset transport variables to their initial values */