Merge tag 'range-macro' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[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,
b962abdc 59 struct ip_vs_cpu_stats __percpu *stats)
b17fc996
HS
60{
61 int i;
d1ee4fea 62 bool add = false;
b17fc996
HS
63
64 for_each_possible_cpu(i) {
65 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
66 unsigned int start;
67 __u64 inbytes, outbytes;
d1ee4fea 68 if (add) {
b17fc996
HS
69 sum->conns += s->ustats.conns;
70 sum->inpkts += s->ustats.inpkts;
71 sum->outpkts += s->ustats.outpkts;
72 do {
4a569c0c 73 start = u64_stats_fetch_begin(&s->syncp);
b17fc996
HS
74 inbytes = s->ustats.inbytes;
75 outbytes = s->ustats.outbytes;
4a569c0c 76 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
77 sum->inbytes += inbytes;
78 sum->outbytes += outbytes;
79 } else {
d1ee4fea 80 add = true;
b17fc996
HS
81 sum->conns = s->ustats.conns;
82 sum->inpkts = s->ustats.inpkts;
83 sum->outpkts = s->ustats.outpkts;
84 do {
4a569c0c 85 start = u64_stats_fetch_begin(&s->syncp);
b17fc996
HS
86 sum->inbytes = s->ustats.inbytes;
87 sum->outbytes = s->ustats.outbytes;
4a569c0c 88 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
89 }
90 }
91}
92
93
1da177e4
LT
94static void estimation_timer(unsigned long arg)
95{
96 struct ip_vs_estimator *e;
97 struct ip_vs_stats *s;
98 u32 n_conns;
99 u32 n_inpkts, n_outpkts;
100 u64 n_inbytes, n_outbytes;
101 u32 rate;
29c2026f
HS
102 struct net *net = (struct net *)arg;
103 struct netns_ipvs *ipvs;
1da177e4 104
29c2026f
HS
105 ipvs = net_ipvs(net);
106 spin_lock(&ipvs->est_lock);
107 list_for_each_entry(e, &ipvs->est_list, list) {
3a14a313 108 s = container_of(e, struct ip_vs_stats, est);
1da177e4
LT
109
110 spin_lock(&s->lock);
2a0751af 111 ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
e9c0ce23
SW
112 n_conns = s->ustats.conns;
113 n_inpkts = s->ustats.inpkts;
114 n_outpkts = s->ustats.outpkts;
115 n_inbytes = s->ustats.inbytes;
116 n_outbytes = s->ustats.outbytes;
1da177e4
LT
117
118 /* scaled by 2^10, but divided 2 seconds */
29c2026f 119 rate = (n_conns - e->last_conns) << 9;
1da177e4 120 e->last_conns = n_conns;
29c2026f 121 e->cps += ((long)rate - (long)e->cps) >> 2;
1da177e4 122
29c2026f 123 rate = (n_inpkts - e->last_inpkts) << 9;
1da177e4 124 e->last_inpkts = n_inpkts;
29c2026f 125 e->inpps += ((long)rate - (long)e->inpps) >> 2;
1da177e4 126
29c2026f 127 rate = (n_outpkts - e->last_outpkts) << 9;
1da177e4 128 e->last_outpkts = n_outpkts;
29c2026f 129 e->outpps += ((long)rate - (long)e->outpps) >> 2;
1da177e4 130
29c2026f 131 rate = (n_inbytes - e->last_inbytes) << 4;
1da177e4 132 e->last_inbytes = n_inbytes;
29c2026f 133 e->inbps += ((long)rate - (long)e->inbps) >> 2;
1da177e4 134
29c2026f 135 rate = (n_outbytes - e->last_outbytes) << 4;
1da177e4 136 e->last_outbytes = n_outbytes;
29c2026f 137 e->outbps += ((long)rate - (long)e->outbps) >> 2;
1da177e4
LT
138 spin_unlock(&s->lock);
139 }
29c2026f
HS
140 spin_unlock(&ipvs->est_lock);
141 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
1da177e4
LT
142}
143
6ef757f9 144void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
1da177e4 145{
29c2026f 146 struct netns_ipvs *ipvs = net_ipvs(net);
3a14a313 147 struct ip_vs_estimator *est = &stats->est;
1da177e4 148
3a14a313 149 INIT_LIST_HEAD(&est->list);
1da177e4 150
29c2026f
HS
151 spin_lock_bh(&ipvs->est_lock);
152 list_add(&est->list, &ipvs->est_list);
153 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
154}
155
6ef757f9 156void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
1da177e4 157{
29c2026f 158 struct netns_ipvs *ipvs = net_ipvs(net);
3a14a313
SW
159 struct ip_vs_estimator *est = &stats->est;
160
29c2026f 161 spin_lock_bh(&ipvs->est_lock);
3a14a313 162 list_del(&est->list);
29c2026f 163 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
164}
165
166void ip_vs_zero_estimator(struct ip_vs_stats *stats)
167{
3a14a313 168 struct ip_vs_estimator *est = &stats->est;
55a3d4e1
JA
169 struct ip_vs_stats_user *u = &stats->ustats;
170
171 /* reset counters, caller must hold the stats->lock lock */
172 est->last_inbytes = u->inbytes;
173 est->last_outbytes = u->outbytes;
174 est->last_conns = u->conns;
175 est->last_inpkts = u->inpkts;
176 est->last_outpkts = u->outpkts;
3a14a313
SW
177 est->cps = 0;
178 est->inpps = 0;
179 est->outpps = 0;
180 est->inbps = 0;
181 est->outbps = 0;
1da177e4 182}
a919cf4b 183
ea9f22cc
JA
184/* Get decoded rates */
185void ip_vs_read_estimator(struct ip_vs_stats_user *dst,
186 struct ip_vs_stats *stats)
187{
188 struct ip_vs_estimator *e = &stats->est;
189
190 dst->cps = (e->cps + 0x1FF) >> 10;
191 dst->inpps = (e->inpps + 0x1FF) >> 10;
192 dst->outpps = (e->outpps + 0x1FF) >> 10;
193 dst->inbps = (e->inbps + 0xF) >> 5;
194 dst->outbps = (e->outbps + 0xF) >> 5;
195}
196
503cf15a 197int __net_init ip_vs_estimator_net_init(struct net *net)
61b1ab45 198{
29c2026f
HS
199 struct netns_ipvs *ipvs = net_ipvs(net);
200
29c2026f
HS
201 INIT_LIST_HEAD(&ipvs->est_list);
202 spin_lock_init(&ipvs->est_lock);
203 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net);
204 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
61b1ab45
HS
205 return 0;
206}
207
503cf15a 208void __net_exit ip_vs_estimator_net_cleanup(struct net *net)
29c2026f
HS
209{
210 del_timer_sync(&net_ipvs(net)->est_timer);
211}
This page took 1.132435 seconds and 5 git commands to generate.