2 * ip_vs_est.c: simple rate estimator for IPVS
4 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 * Changes: Hans Schillstrom <hans.schillstrom@ericsson.com>
12 * Network name space (netns) aware.
13 * Global data moved to netns i.e struct netns_ipvs
14 * Affected data: est_list and est_lock.
15 * estimation_timer() runs with timer per netns.
16 * get_stats()) do the per cpu summing.
19 #define KMSG_COMPONENT "IPVS"
20 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
22 #include <linux/kernel.h>
23 #include <linux/jiffies.h>
24 #include <linux/types.h>
25 #include <linux/interrupt.h>
26 #include <linux/sysctl.h>
27 #include <linux/list.h>
29 #include <net/ip_vs.h>
32 This code is to estimate rate in a shorter interval (such as 8
33 seconds) for virtual services and real servers. For measure rate in a
34 long interval, it is easy to implement a user level daemon which
35 periodically reads those statistical counters and measure rate.
37 Currently, the measurement is activated by slow timer handler. Hope
38 this measurement will not introduce too much load.
40 We measure rate during the last 8 seconds every 2 seconds:
42 avgrate = avgrate*(1-W) + rate*W
48 * The stored value for average bps is scaled by 2^5, so that maximal
49 rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
51 * A lot code is taken from net/sched/estimator.c
56 * Make a summary from each cpu
58 static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
59 struct ip_vs_cpu_stats *stats)
63 for_each_possible_cpu(i) {
64 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
66 __u64 inbytes, outbytes;
68 sum->conns += s->ustats.conns;
69 sum->inpkts += s->ustats.inpkts;
70 sum->outpkts += s->ustats.outpkts;
72 start = u64_stats_fetch_begin(&s->syncp);
73 inbytes = s->ustats.inbytes;
74 outbytes = s->ustats.outbytes;
75 } while (u64_stats_fetch_retry(&s->syncp, start));
76 sum->inbytes += inbytes;
77 sum->outbytes += outbytes;
79 sum->conns = s->ustats.conns;
80 sum->inpkts = s->ustats.inpkts;
81 sum->outpkts = s->ustats.outpkts;
83 start = u64_stats_fetch_begin(&s->syncp);
84 sum->inbytes = s->ustats.inbytes;
85 sum->outbytes = s->ustats.outbytes;
86 } while (u64_stats_fetch_retry(&s->syncp, start));
92 static void estimation_timer(unsigned long arg)
94 struct ip_vs_estimator *e;
95 struct ip_vs_stats *s;
97 u32 n_inpkts, n_outpkts;
98 u64 n_inbytes, n_outbytes;
100 struct net *net = (struct net *)arg;
101 struct netns_ipvs *ipvs;
103 ipvs = net_ipvs(net);
104 ip_vs_read_cpu_stats(&ipvs->tot_stats->ustats, ipvs->cpustats);
105 spin_lock(&ipvs->est_lock);
106 list_for_each_entry(e, &ipvs->est_list, list) {
107 s = container_of(e, struct ip_vs_stats, est);
109 ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
111 n_conns = s->ustats.conns;
112 n_inpkts = s->ustats.inpkts;
113 n_outpkts = s->ustats.outpkts;
114 n_inbytes = s->ustats.inbytes;
115 n_outbytes = s->ustats.outbytes;
117 /* scaled by 2^10, but divided 2 seconds */
118 rate = (n_conns - e->last_conns) << 9;
119 e->last_conns = n_conns;
120 e->cps += ((long)rate - (long)e->cps) >> 2;
121 s->ustats.cps = (e->cps + 0x1FF) >> 10;
123 rate = (n_inpkts - e->last_inpkts) << 9;
124 e->last_inpkts = n_inpkts;
125 e->inpps += ((long)rate - (long)e->inpps) >> 2;
126 s->ustats.inpps = (e->inpps + 0x1FF) >> 10;
128 rate = (n_outpkts - e->last_outpkts) << 9;
129 e->last_outpkts = n_outpkts;
130 e->outpps += ((long)rate - (long)e->outpps) >> 2;
131 s->ustats.outpps = (e->outpps + 0x1FF) >> 10;
133 rate = (n_inbytes - e->last_inbytes) << 4;
134 e->last_inbytes = n_inbytes;
135 e->inbps += ((long)rate - (long)e->inbps) >> 2;
136 s->ustats.inbps = (e->inbps + 0xF) >> 5;
138 rate = (n_outbytes - e->last_outbytes) << 4;
139 e->last_outbytes = n_outbytes;
140 e->outbps += ((long)rate - (long)e->outbps) >> 2;
141 s->ustats.outbps = (e->outbps + 0xF) >> 5;
142 spin_unlock(&s->lock);
144 spin_unlock(&ipvs->est_lock);
145 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
148 void ip_vs_new_estimator(struct net *net, struct ip_vs_stats *stats)
150 struct netns_ipvs *ipvs = net_ipvs(net);
151 struct ip_vs_estimator *est = &stats->est;
153 INIT_LIST_HEAD(&est->list);
155 est->last_conns = stats->ustats.conns;
156 est->cps = stats->ustats.cps<<10;
158 est->last_inpkts = stats->ustats.inpkts;
159 est->inpps = stats->ustats.inpps<<10;
161 est->last_outpkts = stats->ustats.outpkts;
162 est->outpps = stats->ustats.outpps<<10;
164 est->last_inbytes = stats->ustats.inbytes;
165 est->inbps = stats->ustats.inbps<<5;
167 est->last_outbytes = stats->ustats.outbytes;
168 est->outbps = stats->ustats.outbps<<5;
170 spin_lock_bh(&ipvs->est_lock);
171 list_add(&est->list, &ipvs->est_list);
172 spin_unlock_bh(&ipvs->est_lock);
175 void ip_vs_kill_estimator(struct net *net, struct ip_vs_stats *stats)
177 struct netns_ipvs *ipvs = net_ipvs(net);
178 struct ip_vs_estimator *est = &stats->est;
180 spin_lock_bh(&ipvs->est_lock);
181 list_del(&est->list);
182 spin_unlock_bh(&ipvs->est_lock);
185 void ip_vs_zero_estimator(struct ip_vs_stats *stats)
187 struct ip_vs_estimator *est = &stats->est;
189 /* set counters zero, caller must hold the stats->lock lock */
190 est->last_inbytes = 0;
191 est->last_outbytes = 0;
193 est->last_inpkts = 0;
194 est->last_outpkts = 0;
202 static int __net_init __ip_vs_estimator_init(struct net *net)
204 struct netns_ipvs *ipvs = net_ipvs(net);
206 INIT_LIST_HEAD(&ipvs->est_list);
207 spin_lock_init(&ipvs->est_lock);
208 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net);
209 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
213 static void __net_exit __ip_vs_estimator_exit(struct net *net)
215 del_timer_sync(&net_ipvs(net)->est_timer);
217 static struct pernet_operations ip_vs_app_ops = {
218 .init = __ip_vs_estimator_init,
219 .exit = __ip_vs_estimator_exit,
222 int __init ip_vs_estimator_init(void)
226 rv = register_pernet_subsys(&ip_vs_app_ops);
230 void ip_vs_estimator_cleanup(void)
232 unregister_pernet_subsys(&ip_vs_app_ops);