]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/netfilter/ipvs/ip_vs_est.c
ipvs: Pass ipvs not net to ip_vs_start_estimator aned ip_vs_stop_estimator
[mirror_ubuntu-artful-kernel.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
cd67cd5e 48 * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10.
1da177e4 49
cd67cd5e
JA
50 * Netlink users can see 64-bit values but sockopt users are restricted
51 to 32-bit values for conns, packets, bps, cps and pps.
52
53 * A lot of code is taken from net/core/gen_estimator.c
1da177e4
LT
54 */
55
56
b17fc996
HS
57/*
58 * Make a summary from each cpu
59 */
cd67cd5e 60static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
b962abdc 61 struct ip_vs_cpu_stats __percpu *stats)
b17fc996
HS
62{
63 int i;
d1ee4fea 64 bool add = false;
b17fc996
HS
65
66 for_each_possible_cpu(i) {
67 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
68 unsigned int start;
cd67cd5e
JA
69 u64 conns, inpkts, outpkts, inbytes, outbytes;
70
d1ee4fea 71 if (add) {
b17fc996 72 do {
4a569c0c 73 start = u64_stats_fetch_begin(&s->syncp);
cd67cd5e
JA
74 conns = s->cnt.conns;
75 inpkts = s->cnt.inpkts;
76 outpkts = s->cnt.outpkts;
77 inbytes = s->cnt.inbytes;
78 outbytes = s->cnt.outbytes;
4a569c0c 79 } while (u64_stats_fetch_retry(&s->syncp, start));
cd67cd5e
JA
80 sum->conns += conns;
81 sum->inpkts += inpkts;
82 sum->outpkts += outpkts;
b17fc996
HS
83 sum->inbytes += inbytes;
84 sum->outbytes += outbytes;
85 } else {
d1ee4fea 86 add = true;
b17fc996 87 do {
4a569c0c 88 start = u64_stats_fetch_begin(&s->syncp);
cd67cd5e
JA
89 sum->conns = s->cnt.conns;
90 sum->inpkts = s->cnt.inpkts;
91 sum->outpkts = s->cnt.outpkts;
92 sum->inbytes = s->cnt.inbytes;
93 sum->outbytes = s->cnt.outbytes;
4a569c0c 94 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
95 }
96 }
97}
98
99
1da177e4
LT
100static void estimation_timer(unsigned long arg)
101{
102 struct ip_vs_estimator *e;
103 struct ip_vs_stats *s;
cd67cd5e 104 u64 rate;
29c2026f
HS
105 struct net *net = (struct net *)arg;
106 struct netns_ipvs *ipvs;
1da177e4 107
29c2026f
HS
108 ipvs = net_ipvs(net);
109 spin_lock(&ipvs->est_lock);
110 list_for_each_entry(e, &ipvs->est_list, list) {
3a14a313 111 s = container_of(e, struct ip_vs_stats, est);
1da177e4
LT
112
113 spin_lock(&s->lock);
cd67cd5e 114 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
1da177e4
LT
115
116 /* scaled by 2^10, but divided 2 seconds */
cd67cd5e
JA
117 rate = (s->kstats.conns - e->last_conns) << 9;
118 e->last_conns = s->kstats.conns;
119 e->cps += ((s64)rate - (s64)e->cps) >> 2;
120
121 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
122 e->last_inpkts = s->kstats.inpkts;
123 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
124
125 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
126 e->last_outpkts = s->kstats.outpkts;
127 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
128
129 /* scaled by 2^5, but divided 2 seconds */
130 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
131 e->last_inbytes = s->kstats.inbytes;
132 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
133
134 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
135 e->last_outbytes = s->kstats.outbytes;
136 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
1da177e4
LT
137 spin_unlock(&s->lock);
138 }
29c2026f
HS
139 spin_unlock(&ipvs->est_lock);
140 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
1da177e4
LT
141}
142
0f34d54b 143void ip_vs_start_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
1da177e4 144{
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
0f34d54b 154void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
1da177e4 155{
3a14a313
SW
156 struct ip_vs_estimator *est = &stats->est;
157
29c2026f 158 spin_lock_bh(&ipvs->est_lock);
3a14a313 159 list_del(&est->list);
29c2026f 160 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
161}
162
163void ip_vs_zero_estimator(struct ip_vs_stats *stats)
164{
3a14a313 165 struct ip_vs_estimator *est = &stats->est;
cd67cd5e 166 struct ip_vs_kstats *k = &stats->kstats;
55a3d4e1
JA
167
168 /* reset counters, caller must hold the stats->lock lock */
cd67cd5e
JA
169 est->last_inbytes = k->inbytes;
170 est->last_outbytes = k->outbytes;
171 est->last_conns = k->conns;
172 est->last_inpkts = k->inpkts;
173 est->last_outpkts = k->outpkts;
3a14a313
SW
174 est->cps = 0;
175 est->inpps = 0;
176 est->outpps = 0;
177 est->inbps = 0;
178 est->outbps = 0;
1da177e4 179}
a919cf4b 180
ea9f22cc 181/* Get decoded rates */
cd67cd5e 182void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
ea9f22cc
JA
183{
184 struct ip_vs_estimator *e = &stats->est;
185
186 dst->cps = (e->cps + 0x1FF) >> 10;
187 dst->inpps = (e->inpps + 0x1FF) >> 10;
188 dst->outpps = (e->outpps + 0x1FF) >> 10;
189 dst->inbps = (e->inbps + 0xF) >> 5;
190 dst->outbps = (e->outbps + 0xF) >> 5;
191}
192
503cf15a 193int __net_init ip_vs_estimator_net_init(struct net *net)
61b1ab45 194{
29c2026f
HS
195 struct netns_ipvs *ipvs = net_ipvs(net);
196
29c2026f
HS
197 INIT_LIST_HEAD(&ipvs->est_list);
198 spin_lock_init(&ipvs->est_lock);
199 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net);
200 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
61b1ab45
HS
201 return 0;
202}
203
503cf15a 204void __net_exit ip_vs_estimator_net_cleanup(struct net *net)
29c2026f
HS
205{
206 del_timer_sync(&net_ipvs(net)->est_timer);
207}