1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * net/sched/gen_estimator.c Simple rate estimator.
5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * Eric Dumazet <edumazet@google.com>
9 * Jamal Hadi Salim - moved it to net/core and reshulfed
10 * names to make it usable in general net subsystem.
13 #include <linux/uaccess.h>
14 #include <linux/bitops.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/jiffies.h>
19 #include <linux/string.h>
21 #include <linux/socket.h>
22 #include <linux/sockios.h>
24 #include <linux/errno.h>
25 #include <linux/interrupt.h>
26 #include <linux/netdevice.h>
27 #include <linux/skbuff.h>
28 #include <linux/rtnetlink.h>
29 #include <linux/init.h>
30 #include <linux/slab.h>
31 #include <linux/seqlock.h>
33 #include <net/gen_stats.h>
35 /* This code is NOT intended to be used for statistics collection,
36 * its purpose is to provide a base for statistical multiplexing
37 * for controlled load service.
38 * If you need only statistics, run a user level daemon which
39 * periodically reads byte counters.
42 struct net_rate_estimator
{
43 struct gnet_stats_basic_sync
*bstats
;
44 spinlock_t
*stats_lock
;
46 struct gnet_stats_basic_sync __percpu
*cpu_bstats
;
48 u8 intvl_log
; /* period : (250ms << intvl_log) */
57 unsigned long next_jiffies
;
58 struct timer_list timer
;
62 static void est_fetch_counters(struct net_rate_estimator
*e
,
63 struct gnet_stats_basic_sync
*b
)
65 gnet_stats_basic_sync_init(b
);
67 spin_lock(e
->stats_lock
);
69 gnet_stats_add_basic(b
, e
->cpu_bstats
, e
->bstats
, e
->running
);
72 spin_unlock(e
->stats_lock
);
76 static void est_timer(struct timer_list
*t
)
78 struct net_rate_estimator
*est
= from_timer(est
, t
, timer
);
79 struct gnet_stats_basic_sync b
;
80 u64 b_bytes
, b_packets
;
83 est_fetch_counters(est
, &b
);
84 b_bytes
= u64_stats_read(&b
.bytes
);
85 b_packets
= u64_stats_read(&b
.packets
);
87 brate
= (b_bytes
- est
->last_bytes
) << (10 - est
->intvl_log
);
88 brate
= (brate
>> est
->ewma_log
) - (est
->avbps
>> est
->ewma_log
);
90 rate
= (b_packets
- est
->last_packets
) << (10 - est
->intvl_log
);
91 rate
= (rate
>> est
->ewma_log
) - (est
->avpps
>> est
->ewma_log
);
93 write_seqcount_begin(&est
->seq
);
96 write_seqcount_end(&est
->seq
);
98 est
->last_bytes
= b_bytes
;
99 est
->last_packets
= b_packets
;
101 est
->next_jiffies
+= ((HZ
/4) << est
->intvl_log
);
103 if (unlikely(time_after_eq(jiffies
, est
->next_jiffies
))) {
104 /* Ouch... timer was delayed. */
105 est
->next_jiffies
= jiffies
+ 1;
107 mod_timer(&est
->timer
, est
->next_jiffies
);
111 * gen_new_estimator - create a new rate estimator
112 * @bstats: basic statistics
113 * @cpu_bstats: bstats per cpu
114 * @rate_est: rate estimator statistics
115 * @lock: lock for statistics and control path
116 * @running: true if @bstats represents a running qdisc, thus @bstats'
117 * internal values might change during basic reads. Only used
118 * if @bstats_cpu is NULL
119 * @opt: rate estimator configuration TLV
121 * Creates a new rate estimator with &bstats as source and &rate_est
122 * as destination. A new timer with the interval specified in the
123 * configuration TLV is created. Upon each interval, the latest statistics
124 * will be read from &bstats and the estimated rate will be stored in
125 * &rate_est with the statistics lock grabbed during this period.
127 * Returns 0 on success or a negative error code.
130 int gen_new_estimator(struct gnet_stats_basic_sync
*bstats
,
131 struct gnet_stats_basic_sync __percpu
*cpu_bstats
,
132 struct net_rate_estimator __rcu
**rate_est
,
137 struct gnet_estimator
*parm
= nla_data(opt
);
138 struct net_rate_estimator
*old
, *est
;
139 struct gnet_stats_basic_sync b
;
142 if (nla_len(opt
) < sizeof(*parm
))
145 /* allowed timer periods are :
146 * -2 : 250ms, -1 : 500ms, 0 : 1 sec
147 * 1 : 2 sec, 2 : 4 sec, 3 : 8 sec
149 if (parm
->interval
< -2 || parm
->interval
> 3)
152 if (parm
->ewma_log
== 0 || parm
->ewma_log
>= 31)
155 est
= kzalloc(sizeof(*est
), GFP_KERNEL
);
159 seqcount_init(&est
->seq
);
160 intvl_log
= parm
->interval
+ 2;
161 est
->bstats
= bstats
;
162 est
->stats_lock
= lock
;
163 est
->running
= running
;
164 est
->ewma_log
= parm
->ewma_log
;
165 est
->intvl_log
= intvl_log
;
166 est
->cpu_bstats
= cpu_bstats
;
170 est_fetch_counters(est
, &b
);
173 est
->last_bytes
= u64_stats_read(&b
.bytes
);
174 est
->last_packets
= u64_stats_read(&b
.packets
);
178 old
= rcu_dereference_protected(*rate_est
, 1);
180 del_timer_sync(&old
->timer
);
181 est
->avbps
= old
->avbps
;
182 est
->avpps
= old
->avpps
;
185 est
->next_jiffies
= jiffies
+ ((HZ
/4) << intvl_log
);
186 timer_setup(&est
->timer
, est_timer
, 0);
187 mod_timer(&est
->timer
, est
->next_jiffies
);
189 rcu_assign_pointer(*rate_est
, est
);
191 spin_unlock_bh(lock
);
196 EXPORT_SYMBOL(gen_new_estimator
);
199 * gen_kill_estimator - remove a rate estimator
200 * @rate_est: rate estimator
202 * Removes the rate estimator.
205 void gen_kill_estimator(struct net_rate_estimator __rcu
**rate_est
)
207 struct net_rate_estimator
*est
;
209 est
= unrcu_pointer(xchg(rate_est
, NULL
));
211 timer_shutdown_sync(&est
->timer
);
215 EXPORT_SYMBOL(gen_kill_estimator
);
218 * gen_replace_estimator - replace rate estimator configuration
219 * @bstats: basic statistics
220 * @cpu_bstats: bstats per cpu
221 * @rate_est: rate estimator statistics
222 * @lock: lock for statistics and control path
223 * @running: true if @bstats represents a running qdisc, thus @bstats'
224 * internal values might change during basic reads. Only used
225 * if @cpu_bstats is NULL
226 * @opt: rate estimator configuration TLV
228 * Replaces the configuration of a rate estimator by calling
229 * gen_kill_estimator() and gen_new_estimator().
231 * Returns 0 on success or a negative error code.
233 int gen_replace_estimator(struct gnet_stats_basic_sync
*bstats
,
234 struct gnet_stats_basic_sync __percpu
*cpu_bstats
,
235 struct net_rate_estimator __rcu
**rate_est
,
237 bool running
, struct nlattr
*opt
)
239 return gen_new_estimator(bstats
, cpu_bstats
, rate_est
,
242 EXPORT_SYMBOL(gen_replace_estimator
);
245 * gen_estimator_active - test if estimator is currently in use
246 * @rate_est: rate estimator
248 * Returns true if estimator is active, and false if not.
250 bool gen_estimator_active(struct net_rate_estimator __rcu
**rate_est
)
252 return !!rcu_access_pointer(*rate_est
);
254 EXPORT_SYMBOL(gen_estimator_active
);
256 bool gen_estimator_read(struct net_rate_estimator __rcu
**rate_est
,
257 struct gnet_stats_rate_est64
*sample
)
259 struct net_rate_estimator
*est
;
263 est
= rcu_dereference(*rate_est
);
270 seq
= read_seqcount_begin(&est
->seq
);
271 sample
->bps
= est
->avbps
>> 8;
272 sample
->pps
= est
->avpps
>> 8;
273 } while (read_seqcount_retry(&est
->seq
, seq
));
278 EXPORT_SYMBOL(gen_estimator_read
);