2 * net/sched/gen_estimator.c Simple rate estimator.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 * Eric Dumazet <edumazet@google.com>
13 * Jamal Hadi Salim - moved it to net/core and reshulfed
14 * names to make it usable in general net subsystem.
17 #include <linux/uaccess.h>
18 #include <linux/bitops.h>
19 #include <linux/module.h>
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/jiffies.h>
23 #include <linux/string.h>
25 #include <linux/socket.h>
26 #include <linux/sockios.h>
28 #include <linux/errno.h>
29 #include <linux/interrupt.h>
30 #include <linux/netdevice.h>
31 #include <linux/skbuff.h>
32 #include <linux/rtnetlink.h>
33 #include <linux/init.h>
34 #include <linux/slab.h>
35 #include <linux/seqlock.h>
37 #include <net/gen_stats.h>
39 /* This code is NOT intended to be used for statistics collection,
40 * its purpose is to provide a base for statistical multiplexing
41 * for controlled load service.
42 * If you need only statistics, run a user level daemon which
43 * periodically reads byte counters.
46 struct net_rate_estimator
{
47 struct gnet_stats_basic_packed
*bstats
;
48 spinlock_t
*stats_lock
;
50 struct gnet_stats_basic_cpu __percpu
*cpu_bstats
;
52 u8 intvl_log
; /* period : (250ms << intvl_log) */
61 unsigned long next_jiffies
;
62 struct timer_list timer
;
66 static void est_fetch_counters(struct net_rate_estimator
*e
,
67 struct gnet_stats_basic_packed
*b
)
70 spin_lock(e
->stats_lock
);
72 __gnet_stats_copy_basic(e
->running
, b
, e
->cpu_bstats
, e
->bstats
);
75 spin_unlock(e
->stats_lock
);
79 static void est_timer(unsigned long arg
)
81 struct net_rate_estimator
*est
= (struct net_rate_estimator
*)arg
;
82 struct gnet_stats_basic_packed b
;
85 est_fetch_counters(est
, &b
);
86 brate
= (b
.bytes
- est
->last_bytes
) << (10 - est
->ewma_log
- est
->intvl_log
);
87 brate
-= (est
->avbps
>> est
->ewma_log
);
89 rate
= (u64
)(b
.packets
- est
->last_packets
) << (10 - est
->ewma_log
- est
->intvl_log
);
90 rate
-= (est
->avpps
>> est
->ewma_log
);
92 write_seqcount_begin(&est
->seq
);
95 write_seqcount_end(&est
->seq
);
97 est
->last_bytes
= b
.bytes
;
98 est
->last_packets
= b
.packets
;
100 est
->next_jiffies
+= ((HZ
/4) << est
->intvl_log
);
102 if (unlikely(time_after_eq(jiffies
, est
->next_jiffies
))) {
103 /* Ouch... timer was delayed. */
104 est
->next_jiffies
= jiffies
+ 1;
106 mod_timer(&est
->timer
, est
->next_jiffies
);
110 * gen_new_estimator - create a new rate estimator
111 * @bstats: basic statistics
112 * @cpu_bstats: bstats per cpu
113 * @rate_est: rate estimator statistics
114 * @stats_lock: statistics lock
115 * @running: qdisc running seqcount
116 * @opt: rate estimator configuration TLV
118 * Creates a new rate estimator with &bstats as source and &rate_est
119 * as destination. A new timer with the interval specified in the
120 * configuration TLV is created. Upon each interval, the latest statistics
121 * will be read from &bstats and the estimated rate will be stored in
122 * &rate_est with the statistics lock grabbed during this period.
124 * Returns 0 on success or a negative error code.
127 int gen_new_estimator(struct gnet_stats_basic_packed
*bstats
,
128 struct gnet_stats_basic_cpu __percpu
*cpu_bstats
,
129 struct net_rate_estimator __rcu
**rate_est
,
130 spinlock_t
*stats_lock
,
134 struct gnet_estimator
*parm
= nla_data(opt
);
135 struct net_rate_estimator
*old
, *est
;
136 struct gnet_stats_basic_packed b
;
139 if (nla_len(opt
) < sizeof(*parm
))
142 /* allowed timer periods are :
143 * -2 : 250ms, -1 : 500ms, 0 : 1 sec
144 * 1 : 2 sec, 2 : 4 sec, 3 : 8 sec
146 if (parm
->interval
< -2 || parm
->interval
> 3)
149 est
= kzalloc(sizeof(*est
), GFP_KERNEL
);
153 seqcount_init(&est
->seq
);
154 intvl_log
= parm
->interval
+ 2;
155 est
->bstats
= bstats
;
156 est
->stats_lock
= stats_lock
;
157 est
->running
= running
;
158 est
->ewma_log
= parm
->ewma_log
;
159 est
->intvl_log
= intvl_log
;
160 est
->cpu_bstats
= cpu_bstats
;
162 est_fetch_counters(est
, &b
);
163 est
->last_bytes
= b
.bytes
;
164 est
->last_packets
= b
.packets
;
165 old
= rcu_dereference_protected(*rate_est
, 1);
167 del_timer_sync(&old
->timer
);
168 est
->avbps
= old
->avbps
;
169 est
->avpps
= old
->avpps
;
172 est
->next_jiffies
= jiffies
+ ((HZ
/4) << intvl_log
);
173 setup_timer(&est
->timer
, est_timer
, (unsigned long)est
);
174 mod_timer(&est
->timer
, est
->next_jiffies
);
176 rcu_assign_pointer(*rate_est
, est
);
181 EXPORT_SYMBOL(gen_new_estimator
);
184 * gen_kill_estimator - remove a rate estimator
185 * @rate_est: rate estimator
187 * Removes the rate estimator.
190 void gen_kill_estimator(struct net_rate_estimator __rcu
**rate_est
)
192 struct net_rate_estimator
*est
;
194 est
= xchg((__force
struct net_rate_estimator
**)rate_est
, NULL
);
196 del_timer_sync(&est
->timer
);
200 EXPORT_SYMBOL(gen_kill_estimator
);
203 * gen_replace_estimator - replace rate estimator configuration
204 * @bstats: basic statistics
205 * @cpu_bstats: bstats per cpu
206 * @rate_est: rate estimator statistics
207 * @stats_lock: statistics lock
208 * @running: qdisc running seqcount (might be NULL)
209 * @opt: rate estimator configuration TLV
211 * Replaces the configuration of a rate estimator by calling
212 * gen_kill_estimator() and gen_new_estimator().
214 * Returns 0 on success or a negative error code.
216 int gen_replace_estimator(struct gnet_stats_basic_packed
*bstats
,
217 struct gnet_stats_basic_cpu __percpu
*cpu_bstats
,
218 struct net_rate_estimator __rcu
**rate_est
,
219 spinlock_t
*stats_lock
,
220 seqcount_t
*running
, struct nlattr
*opt
)
222 return gen_new_estimator(bstats
, cpu_bstats
, rate_est
,
223 stats_lock
, running
, opt
);
225 EXPORT_SYMBOL(gen_replace_estimator
);
228 * gen_estimator_active - test if estimator is currently in use
229 * @rate_est: rate estimator
231 * Returns true if estimator is active, and false if not.
233 bool gen_estimator_active(struct net_rate_estimator __rcu
**rate_est
)
235 return !!rcu_access_pointer(*rate_est
);
237 EXPORT_SYMBOL(gen_estimator_active
);
239 bool gen_estimator_read(struct net_rate_estimator __rcu
**rate_est
,
240 struct gnet_stats_rate_est64
*sample
)
242 struct net_rate_estimator
*est
;
246 est
= rcu_dereference(*rate_est
);
253 seq
= read_seqcount_begin(&est
->seq
);
254 sample
->bps
= est
->avbps
>> 8;
255 sample
->pps
= est
->avpps
>> 8;
256 } while (read_seqcount_retry(&est
->seq
, seq
));
261 EXPORT_SYMBOL(gen_estimator_read
);