Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-3.6
[deliverable/linux.git] / net / netfilter / ipvs / ip_vs_est.c
CommitLineData
1da177e4
LT
1/*
2 * ip_vs_est.c: simple rate estimator for IPVS
3 *
1da177e4
LT
4 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
5 *
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.
10 *
29c2026f
HS
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.
1da177e4 17 */
9aada7ac
HE
18
19#define KMSG_COMPONENT "IPVS"
20#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
21
1da177e4 22#include <linux/kernel.h>
14c85021 23#include <linux/jiffies.h>
1da177e4 24#include <linux/types.h>
4ffd2e49 25#include <linux/interrupt.h>
90754f8e 26#include <linux/sysctl.h>
3a14a313 27#include <linux/list.h>
1da177e4
LT
28
29#include <net/ip_vs.h>
30
31/*
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.
36
37 Currently, the measurement is activated by slow timer handler. Hope
38 this measurement will not introduce too much load.
39
40 We measure rate during the last 8 seconds every 2 seconds:
41
42 avgrate = avgrate*(1-W) + rate*W
43
44 where W = 2^(-2)
45
46 NOTES.
47
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.
50
51 * A lot code is taken from net/sched/estimator.c
52 */
53
54
b17fc996
HS
55/*
56 * Make a summary from each cpu
57 */
58static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
59 struct ip_vs_cpu_stats *stats)
60{
61 int i;
62
63 for_each_possible_cpu(i) {
64 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
65 unsigned int start;
66 __u64 inbytes, outbytes;
67 if (i) {
68 sum->conns += s->ustats.conns;
69 sum->inpkts += s->ustats.inpkts;
70 sum->outpkts += s->ustats.outpkts;
71 do {
4a569c0c 72 start = u64_stats_fetch_begin(&s->syncp);
b17fc996
HS
73 inbytes = s->ustats.inbytes;
74 outbytes = s->ustats.outbytes;
4a569c0c 75 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
76 sum->inbytes += inbytes;
77 sum->outbytes += outbytes;
78 } else {
79 sum->conns = s->ustats.conns;
80 sum->inpkts = s->ustats.inpkts;
81 sum->outpkts = s->ustats.outpkts;
82 do {
4a569c0c 83 start = u64_stats_fetch_begin(&s->syncp);
b17fc996
HS
84 sum->inbytes = s->ustats.inbytes;
85 sum->outbytes = s->ustats.outbytes;
4a569c0c 86 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
87 }
88 }
89}
90
91
1da177e4
LT
92static void estimation_timer(unsigned long arg)
93{
94 struct ip_vs_estimator *e;
95 struct ip_vs_stats *s;
96 u32 n_conns;
97 u32 n_inpkts, n_outpkts;
98 u64 n_inbytes, n_outbytes;
99 u32 rate;
29c2026f
HS
100 struct net *net = (struct net *)arg;
101 struct netns_ipvs *ipvs;
1da177e4 102
29c2026f
HS
103 ipvs = net_ipvs(net);
104 spin_lock(&ipvs->est_lock);
105 list_for_each_entry(e, &ipvs->est_list, list) {
3a14a313 106 s = container_of(e, struct ip_vs_stats, est);
1da177e4
LT
107
108 spin_lock(&s->lock);
2a0751af 109 ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
e9c0ce23
SW
110 n_conns = s->ustats.conns;
111 n_inpkts = s->ustats.inpkts;
112 n_outpkts = s->ustats.outpkts;
113 n_inbytes = s->ustats.inbytes;
114 n_outbytes = s->ustats.outbytes;
1da177e4
LT
115
116 /* scaled by 2^10, but divided 2 seconds */
29c2026f 117 rate = (n_conns - e->last_conns) << 9;
1da177e4 118 e->last_conns = n_conns;
29c2026f 119 e->cps += ((long)rate - (long)e->cps) >> 2;
1da177e4 120
29c2026f 121 rate = (n_inpkts - e->last_inpkts) << 9;
1da177e4 122 e->last_inpkts = n_inpkts;
29c2026f 123 e->inpps += ((long)rate - (long)e->inpps) >> 2;
1da177e4 124
29c2026f 125 rate = (n_outpkts - e->last_outpkts) << 9;
1da177e4 126 e->last_outpkts = n_outpkts;
29c2026f 127 e->outpps += ((long)rate - (long)e->outpps) >> 2;
1da177e4 128
29c2026f 129 rate = (n_inbytes - e->last_inbytes) << 4;
1da177e4 130 e->last_inbytes = n_inbytes;
29c2026f 131 e->inbps += ((long)rate - (long)e->inbps) >> 2;
1da177e4 132
29c2026f 133 rate = (n_outbytes - e->last_outbytes) << 4;
1da177e4 134 e->last_outbytes = n_outbytes;
29c2026f 135 e->outbps += ((long)rate - (long)e->outbps) >> 2;
1da177e4
LT
136 spin_unlock(&s->lock);
137 }
29c2026f
HS
138 spin_unlock(&ipvs->est_lock);
139 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
1da177e4
LT
140}
141
6ef757f9 142void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
1da177e4 143{
29c2026f 144 struct netns_ipvs *ipvs = net_ipvs(net);
3a14a313 145 struct ip_vs_estimator *est = &stats->est;
1da177e4 146
3a14a313 147 INIT_LIST_HEAD(&est->list);
1da177e4 148
29c2026f
HS
149 spin_lock_bh(&ipvs->est_lock);
150 list_add(&est->list, &ipvs->est_list);
151 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
152}
153
6ef757f9 154void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
1da177e4 155{
29c2026f 156 struct netns_ipvs *ipvs = net_ipvs(net);
3a14a313
SW
157 struct ip_vs_estimator *est = &stats->est;
158
29c2026f 159 spin_lock_bh(&ipvs->est_lock);
3a14a313 160 list_del(&est->list);
29c2026f 161 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
162}
163
164void ip_vs_zero_estimator(struct ip_vs_stats *stats)
165{
3a14a313 166 struct ip_vs_estimator *est = &stats->est;
55a3d4e1
JA
167 struct ip_vs_stats_user *u = &stats->ustats;
168
169 /* reset counters, caller must hold the stats->lock lock */
170 est->last_inbytes = u->inbytes;
171 est->last_outbytes = u->outbytes;
172 est->last_conns = u->conns;
173 est->last_inpkts = u->inpkts;
174 est->last_outpkts = u->outpkts;
3a14a313
SW
175 est->cps = 0;
176 est->inpps = 0;
177 est->outpps = 0;
178 est->inbps = 0;
179 est->outbps = 0;
1da177e4 180}
a919cf4b 181
ea9f22cc
JA
182/* Get decoded rates */
183void ip_vs_read_estimator(struct ip_vs_stats_user *dst,
184 struct ip_vs_stats *stats)
185{
186 struct ip_vs_estimator *e = &stats->est;
187
188 dst->cps = (e->cps + 0x1FF) >> 10;
189 dst->inpps = (e->inpps + 0x1FF) >> 10;
190 dst->outpps = (e->outpps + 0x1FF) >> 10;
191 dst->inbps = (e->inbps + 0xF) >> 5;
192 dst->outbps = (e->outbps + 0xF) >> 5;
193}
194
7a4f0761 195int __net_init __ip_vs_estimator_init(struct net *net)
61b1ab45 196{
29c2026f
HS
197 struct netns_ipvs *ipvs = net_ipvs(net);
198
29c2026f
HS
199 INIT_LIST_HEAD(&ipvs->est_list);
200 spin_lock_init(&ipvs->est_lock);
201 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net);
202 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
61b1ab45
HS
203 return 0;
204}
205
7a4f0761 206void __net_exit __ip_vs_estimator_cleanup(struct net *net)
29c2026f
HS
207{
208 del_timer_sync(&net_ipvs(net)->est_timer);
209}
61b1ab45 210
a919cf4b
SW
211int __init ip_vs_estimator_init(void)
212{
7a4f0761 213 return 0;
a919cf4b
SW
214}
215
216void ip_vs_estimator_cleanup(void)
217{
a919cf4b 218}
This page took 0.711869 seconds and 5 git commands to generate.