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_packed
*bstats
;
44 spinlock_t
*stats_lock
;
46 struct gnet_stats_basic_cpu __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_packed
*b
)
65 memset(b
, 0, sizeof(*b
));
67 spin_lock(e
->stats_lock
);
69 __gnet_stats_copy_basic(e
->running
, b
, e
->cpu_bstats
, e
->bstats
);
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_packed b
;
82 est_fetch_counters(est
, &b
);
83 brate
= (b
.bytes
- est
->last_bytes
) << (10 - est
->ewma_log
- est
->intvl_log
);
84 brate
-= (est
->avbps
>> est
->ewma_log
);
86 rate
= (b
.packets
- est
->last_packets
) << (10 - est
->ewma_log
- est
->intvl_log
);
87 rate
-= (est
->avpps
>> est
->ewma_log
);
89 write_seqcount_begin(&est
->seq
);
92 write_seqcount_end(&est
->seq
);
94 est
->last_bytes
= b
.bytes
;
95 est
->last_packets
= b
.packets
;
97 est
->next_jiffies
+= ((HZ
/4) << est
->intvl_log
);
99 if (unlikely(time_after_eq(jiffies
, est
->next_jiffies
))) {
100 /* Ouch... timer was delayed. */
101 est
->next_jiffies
= jiffies
+ 1;
103 mod_timer(&est
->timer
, est
->next_jiffies
);
107 * gen_new_estimator - create a new rate estimator
108 * @bstats: basic statistics
109 * @cpu_bstats: bstats per cpu
110 * @rate_est: rate estimator statistics
111 * @lock: lock for statistics and control path
112 * @running: qdisc running seqcount
113 * @opt: rate estimator configuration TLV
115 * Creates a new rate estimator with &bstats as source and &rate_est
116 * as destination. A new timer with the interval specified in the
117 * configuration TLV is created. Upon each interval, the latest statistics
118 * will be read from &bstats and the estimated rate will be stored in
119 * &rate_est with the statistics lock grabbed during this period.
121 * Returns 0 on success or a negative error code.
124 int gen_new_estimator(struct gnet_stats_basic_packed
*bstats
,
125 struct gnet_stats_basic_cpu __percpu
*cpu_bstats
,
126 struct net_rate_estimator __rcu
**rate_est
,
131 struct gnet_estimator
*parm
= nla_data(opt
);
132 struct net_rate_estimator
*old
, *est
;
133 struct gnet_stats_basic_packed b
;
136 if (nla_len(opt
) < sizeof(*parm
))
139 /* allowed timer periods are :
140 * -2 : 250ms, -1 : 500ms, 0 : 1 sec
141 * 1 : 2 sec, 2 : 4 sec, 3 : 8 sec
143 if (parm
->interval
< -2 || parm
->interval
> 3)
146 est
= kzalloc(sizeof(*est
), GFP_KERNEL
);
150 seqcount_init(&est
->seq
);
151 intvl_log
= parm
->interval
+ 2;
152 est
->bstats
= bstats
;
153 est
->stats_lock
= lock
;
154 est
->running
= running
;
155 est
->ewma_log
= parm
->ewma_log
;
156 est
->intvl_log
= intvl_log
;
157 est
->cpu_bstats
= cpu_bstats
;
161 est_fetch_counters(est
, &b
);
164 est
->last_bytes
= b
.bytes
;
165 est
->last_packets
= b
.packets
;
169 old
= rcu_dereference_protected(*rate_est
, 1);
171 del_timer_sync(&old
->timer
);
172 est
->avbps
= old
->avbps
;
173 est
->avpps
= old
->avpps
;
176 est
->next_jiffies
= jiffies
+ ((HZ
/4) << intvl_log
);
177 timer_setup(&est
->timer
, est_timer
, 0);
178 mod_timer(&est
->timer
, est
->next_jiffies
);
180 rcu_assign_pointer(*rate_est
, est
);
182 spin_unlock_bh(lock
);
187 EXPORT_SYMBOL(gen_new_estimator
);
190 * gen_kill_estimator - remove a rate estimator
191 * @rate_est: rate estimator
193 * Removes the rate estimator.
196 void gen_kill_estimator(struct net_rate_estimator __rcu
**rate_est
)
198 struct net_rate_estimator
*est
;
200 est
= xchg((__force
struct net_rate_estimator
**)rate_est
, NULL
);
202 del_timer_sync(&est
->timer
);
206 EXPORT_SYMBOL(gen_kill_estimator
);
209 * gen_replace_estimator - replace rate estimator configuration
210 * @bstats: basic statistics
211 * @cpu_bstats: bstats per cpu
212 * @rate_est: rate estimator statistics
213 * @lock: lock for statistics and control path
214 * @running: qdisc running seqcount (might be NULL)
215 * @opt: rate estimator configuration TLV
217 * Replaces the configuration of a rate estimator by calling
218 * gen_kill_estimator() and gen_new_estimator().
220 * Returns 0 on success or a negative error code.
222 int gen_replace_estimator(struct gnet_stats_basic_packed
*bstats
,
223 struct gnet_stats_basic_cpu __percpu
*cpu_bstats
,
224 struct net_rate_estimator __rcu
**rate_est
,
226 seqcount_t
*running
, struct nlattr
*opt
)
228 return gen_new_estimator(bstats
, cpu_bstats
, rate_est
,
231 EXPORT_SYMBOL(gen_replace_estimator
);
234 * gen_estimator_active - test if estimator is currently in use
235 * @rate_est: rate estimator
237 * Returns true if estimator is active, and false if not.
239 bool gen_estimator_active(struct net_rate_estimator __rcu
**rate_est
)
241 return !!rcu_access_pointer(*rate_est
);
243 EXPORT_SYMBOL(gen_estimator_active
);
245 bool gen_estimator_read(struct net_rate_estimator __rcu
**rate_est
,
246 struct gnet_stats_rate_est64
*sample
)
248 struct net_rate_estimator
*est
;
252 est
= rcu_dereference(*rate_est
);
259 seq
= read_seqcount_begin(&est
->seq
);
260 sample
->bps
= est
->avbps
>> 8;
261 sample
->pps
= est
->avpps
>> 8;
262 } while (read_seqcount_retry(&est
->seq
, seq
));
267 EXPORT_SYMBOL(gen_estimator_read
);