sk_pacing_rate has beed introduced as a u32 field in 2013,
effectively limiting per flow pacing to 34Gbit.

We believe it is time to allow TCP to pace high speed flows
on 64bit hosts, as we now can reach 100Gbit on one TCP flow.

This patch adds no cost for 32bit kernels.

The tcpi_pacing_rate and tcpi_max_pacing_rate were already
exported as 64bit, so iproute2/ss command require no changes.

Unfortunately the SO_MAX_PACING_RATE socket option will stay
32bit and we will need to add a new option to let applications
control high pacing rates.

State      Recv-Q Send-Q Local Address:Port             Peer Address:Port
ESTAB      0      1787144  10.246.9.76:49992             10.246.9.77:36741
                 timer:(on,003ms,0) ino:91863 sk:2 <->
 skmem:(r0,rb540000,t66440,tb2363904,f605944,w1822984,o0,bl0,d0)
 ts sack bbr wscale:8,8 rto:201 rtt:0.057/0.006 mss:1448
 rcvmss:536 advmss:1448
 cwnd:138 ssthresh:178 bytes_acked:256699822585 segs_out:177279177
 segs_in:3916318 data_segs_out:177279175
 bbr:(bw:31276.8Mbps,mrtt:0,pacing_gain:1.25,cwnd_gain:2)
 send 28045.5Mbps lastrcv:73333
 pacing_rate 38705.0Mbps delivery_rate 22997.6Mbps
 busy:73333ms unacked:135 retrans:0/157 rcv_space:14480
 notsent:2085120 minrtt:0.013

Signed-off-by: Eric Dumazet <eduma...@google.com>
---
 include/net/sock.h    |  4 ++--
 net/core/filter.c     |  4 ++--
 net/core/sock.c       |  9 +++++----
 net/ipv4/tcp.c        | 10 +++++-----
 net/ipv4/tcp_bbr.c    |  6 +++---
 net/ipv4/tcp_output.c | 19 +++++++++++--------
 net/sched/sch_fq.c    | 20 ++++++++++++--------
 7 files changed, 40 insertions(+), 32 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 
751549ac0a849144ab0382203ee5c877374523e2..cfaf261936c8787b3a65ce832fd9c871697d00f4
 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -422,8 +422,8 @@ struct sock {
        struct timer_list       sk_timer;
        __u32                   sk_priority;
        __u32                   sk_mark;
-       u32                     sk_pacing_rate; /* bytes per second */
-       u32                     sk_max_pacing_rate;
+       unsigned long           sk_pacing_rate; /* bytes per second */
+       unsigned long           sk_max_pacing_rate;
        struct page_frag        sk_frag;
        netdev_features_t       sk_route_caps;
        netdev_features_t       sk_route_nocaps;
diff --git a/net/core/filter.c b/net/core/filter.c
index 
4bbc6567fcb818e91617bfa9a2fd7fbebbd129f8..80da21b097b8d05eb7b9fa92afa86762334ac0ae
 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3927,8 +3927,8 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, 
bpf_sock,
                        sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
                        sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
                        break;
-               case SO_MAX_PACING_RATE:
-                       sk->sk_max_pacing_rate = val;
+               case SO_MAX_PACING_RATE: /* 32bit version */
+                       sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val;
                        sk->sk_pacing_rate = min(sk->sk_pacing_rate,
                                                 sk->sk_max_pacing_rate);
                        break;
diff --git a/net/core/sock.c b/net/core/sock.c
index 
7e8796a6a0892efbb7dfce67d12b8062b2d5daa9..fdf9fc7d3f9875f2718575078a0f263674c80b4f
 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -998,7 +998,7 @@ int sock_setsockopt(struct socket *sock, int level, int 
optname,
                        cmpxchg(&sk->sk_pacing_status,
                                SK_PACING_NONE,
                                SK_PACING_NEEDED);
-               sk->sk_max_pacing_rate = val;
+               sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val;
                sk->sk_pacing_rate = min(sk->sk_pacing_rate,
                                         sk->sk_max_pacing_rate);
                break;
@@ -1336,7 +1336,8 @@ int sock_getsockopt(struct socket *sock, int level, int 
optname,
 #endif
 
        case SO_MAX_PACING_RATE:
-               v.val = sk->sk_max_pacing_rate;
+               /* 32bit version */
+               v.val = min_t(unsigned long, sk->sk_max_pacing_rate, ~0U);
                break;
 
        case SO_INCOMING_CPU:
@@ -2810,8 +2811,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
 
-       sk->sk_max_pacing_rate = ~0U;
-       sk->sk_pacing_rate = ~0U;
+       sk->sk_max_pacing_rate = ~0UL;
+       sk->sk_pacing_rate = ~0UL;
        sk->sk_pacing_shift = 10;
        sk->sk_incoming_cpu = -1;
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 
43ef83b2330e6238a55c9843580a585d87708e0c..b8ba8fa34effac5138aea76b0d0fc2a9f1c05c4f
 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3111,10 +3111,10 @@ void tcp_get_info(struct sock *sk, struct tcp_info 
*info)
 {
        const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */
        const struct inet_connection_sock *icsk = inet_csk(sk);
+       unsigned long rate;
        u32 now;
        u64 rate64;
        bool slow;
-       u32 rate;
 
        memset(info, 0, sizeof(*info));
        if (sk->sk_type != SOCK_STREAM)
@@ -3124,11 +3124,11 @@ void tcp_get_info(struct sock *sk, struct tcp_info 
*info)
 
        /* Report meaningful fields for all TCP states, including listeners */
        rate = READ_ONCE(sk->sk_pacing_rate);
-       rate64 = rate != ~0U ? rate : ~0ULL;
+       rate64 = (rate != ~0UL) ? rate : ~0ULL;
        info->tcpi_pacing_rate = rate64;
 
        rate = READ_ONCE(sk->sk_max_pacing_rate);
-       rate64 = rate != ~0U ? rate : ~0ULL;
+       rate64 = (rate != ~0UL) ? rate : ~0ULL;
        info->tcpi_max_pacing_rate = rate64;
 
        info->tcpi_reordering = tp->reordering;
@@ -3254,8 +3254,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const 
struct sock *sk)
        const struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *stats;
        struct tcp_info info;
+       unsigned long rate;
        u64 rate64;
-       u32 rate;
 
        stats = alloc_skb(tcp_opt_stats_get_size(), GFP_ATOMIC);
        if (!stats)
@@ -3274,7 +3274,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const 
struct sock *sk)
                          tp->total_retrans, TCP_NLA_PAD);
 
        rate = READ_ONCE(sk->sk_pacing_rate);
-       rate64 = rate != ~0U ? rate : ~0ULL;
+       rate64 = (rate != ~0UL) ? rate : ~0ULL;
        nla_put_u64_64bit(stats, TCP_NLA_PACING_RATE, rate64, TCP_NLA_PAD);
 
        rate64 = tcp_compute_delivery_rate(tp);
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 
a5786e3e2c16ce53a332f29c9a55b9a641eec791..33f4358615e6d63b5c98a30484f12ffae66334a2
 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -219,7 +219,7 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 
rate, int gain)
 }
 
 /* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */
-static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain)
+static unsigned long bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain)
 {
        u64 rate = bw;
 
@@ -258,7 +258,7 @@ static void bbr_set_pacing_rate(struct sock *sk, u32 bw, 
int gain)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bbr *bbr = inet_csk_ca(sk);
-       u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain);
+       unsigned long rate = bbr_bw_to_pacing_rate(sk, bw, gain);
 
        if (unlikely(!bbr->has_seen_rtt && tp->srtt_us))
                bbr_init_pacing_rate_from_rtt(sk);
@@ -280,7 +280,7 @@ static u32 bbr_tso_segs_goal(struct sock *sk)
        /* Sort of tcp_tso_autosize() but ignoring
         * driver provided sk_gso_max_size.
         */
-       bytes = min_t(u32, sk->sk_pacing_rate >> sk->sk_pacing_shift,
+       bytes = min_t(unsigned long, sk->sk_pacing_rate >> sk->sk_pacing_shift,
                      GSO_MAX_SIZE - 1 - MAX_TCP_HEADER);
        segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk));
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 
f14df66a0c858dcb22b8924b9691c375eb5fcbc5..f4aa4109334a043d02b17b18bef346d805dab501
 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -991,14 +991,14 @@ static void tcp_update_skb_after_send(struct sock *sk, 
struct sk_buff *skb)
 
        skb->skb_mstamp_ns = tp->tcp_wstamp_ns;
        if (sk->sk_pacing_status != SK_PACING_NONE) {
-               u32 rate = sk->sk_pacing_rate;
+               unsigned long rate = sk->sk_pacing_rate;
 
                /* Original sch_fq does not pace first 10 MSS
                 * Note that tp->data_segs_out overflows after 2^32 packets,
                 * this is a minor annoyance.
                 */
-               if (rate != ~0U && rate && tp->data_segs_out >= 10) {
-                       tp->tcp_wstamp_ns += div_u64((u64)skb->len * 
NSEC_PER_SEC, rate);
+               if (rate != ~0UL && rate && tp->data_segs_out >= 10) {
+                       tp->tcp_wstamp_ns += div64_ul((u64)skb->len * 
NSEC_PER_SEC, rate);
 
                        tcp_internal_pacing(sk);
                }
@@ -1704,8 +1704,9 @@ static u32 tcp_tso_autosize(const struct sock *sk, 
unsigned int mss_now,
 {
        u32 bytes, segs;
 
-       bytes = min(sk->sk_pacing_rate >> sk->sk_pacing_shift,
-                   sk->sk_gso_max_size - 1 - MAX_TCP_HEADER);
+       bytes = min_t(unsigned long,
+                     sk->sk_pacing_rate >> sk->sk_pacing_shift,
+                     sk->sk_gso_max_size - 1 - MAX_TCP_HEADER);
 
        /* Goal is to send at least one packet per ms,
         * not one big TSO packet every 100 ms.
@@ -2198,10 +2199,12 @@ static bool tcp_pacing_check(const struct sock *sk)
 static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
                                  unsigned int factor)
 {
-       unsigned int limit;
+       unsigned long limit;
 
-       limit = max(2 * skb->truesize, sk->sk_pacing_rate >> 
sk->sk_pacing_shift);
-       limit = min_t(u32, limit,
+       limit = max_t(unsigned long,
+                     2 * skb->truesize,
+                     sk->sk_pacing_rate >> sk->sk_pacing_shift);
+       limit = min_t(unsigned long, limit,
                      sock_net(sk)->ipv4.sysctl_tcp_limit_output_bytes);
        limit <<= factor;
 
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 
338222a6c664b1825aaada4355e2fc0a01db9c73..3923d14095335df61c270f69e50cb7cbfde4c796
 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -92,8 +92,8 @@ struct fq_sched_data {
        u32             quantum;
        u32             initial_quantum;
        u32             flow_refill_delay;
-       u32             flow_max_rate;  /* optional max rate per flow */
        u32             flow_plimit;    /* max packets per flow */
+       unsigned long   flow_max_rate;  /* optional max rate per flow */
        u32             orphan_mask;    /* mask for orphaned skb */
        u32             low_rate_threshold;
        struct rb_root  *fq_root;
@@ -416,7 +416,8 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
        struct fq_flow_head *head;
        struct sk_buff *skb;
        struct fq_flow *f;
-       u32 rate, plen;
+       unsigned long rate;
+       u32 plen;
 
        skb = fq_dequeue_head(sch, &q->internal);
        if (skb)
@@ -485,11 +486,11 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
                if (f->credit > 0)
                        goto out;
        }
-       if (rate != ~0U) {
+       if (rate != ~0UL) {
                u64 len = (u64)plen * NSEC_PER_SEC;
 
                if (likely(rate))
-                       do_div(len, rate);
+                       len = div64_ul(len, rate);
                /* Since socket rate can change later,
                 * clamp the delay to 1 second.
                 * Really, providers of too big packets should be fixed !
@@ -701,9 +702,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt,
                pr_warn_ratelimited("sch_fq: defrate %u ignored.\n",
                                    nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]));
 
-       if (tb[TCA_FQ_FLOW_MAX_RATE])
-               q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
+       if (tb[TCA_FQ_FLOW_MAX_RATE]) {
+               u32 rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
 
+               q->flow_max_rate = (rate == ~0U) ? ~0UL : rate;
+       }
        if (tb[TCA_FQ_LOW_RATE_THRESHOLD])
                q->low_rate_threshold =
                        nla_get_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]);
@@ -766,7 +769,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt,
        q->quantum              = 2 * psched_mtu(qdisc_dev(sch));
        q->initial_quantum      = 10 * psched_mtu(qdisc_dev(sch));
        q->flow_refill_delay    = msecs_to_jiffies(40);
-       q->flow_max_rate        = ~0U;
+       q->flow_max_rate        = ~0UL;
        q->time_next_delayed_flow = ~0ULL;
        q->rate_enable          = 1;
        q->new_flows.first      = NULL;
@@ -802,7 +805,8 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) ||
            nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) ||
            nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) ||
-           nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) ||
+           nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE,
+                       min_t(unsigned long, q->flow_max_rate, ~0U)) ||
            nla_put_u32(skb, TCA_FQ_FLOW_REFILL_DELAY,
                        jiffies_to_usecs(q->flow_refill_delay)) ||
            nla_put_u32(skb, TCA_FQ_ORPHAN_MASK, q->orphan_mask) ||
-- 
2.19.0.605.g01d371f741-goog

Reply via email to