Allow congestion control modules to set a custom pacing time between
the transmission of segments.
Moreover, it is assumed that the time returned by the congestion module
in the past is firm, until the timer expires; therefore, do not re-start
the timer if it is already active.

Signed-off-by: Natale Patriciello <natale.patricie...@gmail.com>
---
 include/net/tcp.h     |  2 ++
 net/ipv4/tcp_output.c | 36 +++++++++++++++++++++++++-----------
 2 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 89974c5286d8..42c7aa96c4cf 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1015,6 +1015,8 @@ struct tcp_congestion_ops {
        /* get info for inet_diag (optional) */
        size_t (*get_info)(struct sock *sk, u32 ext, int *attr,
                           union tcp_cc_info *info);
+       /* get the expiration time for the pacing timer (optional) */
+       u64 (*get_pacing_time)(struct sock *sk);
 
        char            name[TCP_CA_NAME_MAX];
        struct module   *owner;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 0bc9e46a5369..ec5977156c26 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -950,22 +950,36 @@ static bool tcp_needs_internal_pacing(const struct sock 
*sk)
        return smp_load_acquire(&sk->sk_pacing_status) == SK_PACING_NEEDED;
 }
 
+static bool tcp_pacing_timer_check(const struct sock *sk)
+{
+       return hrtimer_active(&tcp_sk(sk)->pacing_timer);
+}
+
 static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb)
 {
+       const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
        u64 len_ns;
-       u32 rate;
 
        if (!tcp_needs_internal_pacing(sk))
                return;
-       rate = sk->sk_pacing_rate;
-       if (!rate || rate == ~0U)
-               return;
-
-       /* Should account for header sizes as sch_fq does,
-        * but lets make things simple.
-        */
-       len_ns = (u64)skb->len * NSEC_PER_SEC;
-       do_div(len_ns, rate);
+
+       if (ca_ops && ca_ops->get_pacing_time) {
+               if (tcp_pacing_timer_check(sk))
+                       return;
+
+               len_ns = ca_ops->get_pacing_time(sk);
+       } else {
+               u32 rate = sk->sk_pacing_rate;
+
+               if (!rate || rate == ~0U)
+                       return;
+
+               /* Should account for header sizes as sch_fq does,
+                * but lets make things simple.
+                */
+               len_ns = (u64)skb->len * NSEC_PER_SEC;
+               do_div(len_ns, rate);
+       }
        hrtimer_start(&tcp_sk(sk)->pacing_timer,
                      ktime_add_ns(ktime_get(), len_ns),
                      HRTIMER_MODE_ABS_PINNED);
@@ -2123,7 +2137,7 @@ static int tcp_mtu_probe(struct sock *sk)
 static bool tcp_pacing_check(const struct sock *sk)
 {
        return tcp_needs_internal_pacing(sk) &&
-              hrtimer_active(&tcp_sk(sk)->pacing_timer);
+               tcp_pacing_timer_check(sk);
 }
 
 /* TCP Small Queues :
-- 
2.14.2

Reply via email to