]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - net/netfilter/ipvs/ip_vs_est.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152
[mirror_ubuntu-kernels.git] / net / netfilter / ipvs / ip_vs_est.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4
LT
2/*
3 * ip_vs_est.c: simple rate estimator for IPVS
4 *
1da177e4
LT
5 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
6 *
29c2026f
HS
7 * Changes: Hans Schillstrom <hans.schillstrom@ericsson.com>
8 * Network name space (netns) aware.
9 * Global data moved to netns i.e struct netns_ipvs
10 * Affected data: est_list and est_lock.
11 * estimation_timer() runs with timer per netns.
12 * get_stats()) do the per cpu summing.
1da177e4 13 */
9aada7ac
HE
14
15#define KMSG_COMPONENT "IPVS"
16#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
17
1da177e4 18#include <linux/kernel.h>
14c85021 19#include <linux/jiffies.h>
1da177e4 20#include <linux/types.h>
4ffd2e49 21#include <linux/interrupt.h>
90754f8e 22#include <linux/sysctl.h>
3a14a313 23#include <linux/list.h>
1da177e4
LT
24
25#include <net/ip_vs.h>
26
27/*
28 This code is to estimate rate in a shorter interval (such as 8
29 seconds) for virtual services and real servers. For measure rate in a
30 long interval, it is easy to implement a user level daemon which
31 periodically reads those statistical counters and measure rate.
32
33 Currently, the measurement is activated by slow timer handler. Hope
34 this measurement will not introduce too much load.
35
36 We measure rate during the last 8 seconds every 2 seconds:
37
38 avgrate = avgrate*(1-W) + rate*W
39
40 where W = 2^(-2)
41
42 NOTES.
43
cd67cd5e 44 * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10.
1da177e4 45
cd67cd5e
JA
46 * Netlink users can see 64-bit values but sockopt users are restricted
47 to 32-bit values for conns, packets, bps, cps and pps.
48
49 * A lot of code is taken from net/core/gen_estimator.c
1da177e4
LT
50 */
51
52
b17fc996
HS
53/*
54 * Make a summary from each cpu
55 */
cd67cd5e 56static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
b962abdc 57 struct ip_vs_cpu_stats __percpu *stats)
b17fc996
HS
58{
59 int i;
d1ee4fea 60 bool add = false;
b17fc996
HS
61
62 for_each_possible_cpu(i) {
63 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
64 unsigned int start;
cd67cd5e
JA
65 u64 conns, inpkts, outpkts, inbytes, outbytes;
66
d1ee4fea 67 if (add) {
b17fc996 68 do {
4a569c0c 69 start = u64_stats_fetch_begin(&s->syncp);
cd67cd5e
JA
70 conns = s->cnt.conns;
71 inpkts = s->cnt.inpkts;
72 outpkts = s->cnt.outpkts;
73 inbytes = s->cnt.inbytes;
74 outbytes = s->cnt.outbytes;
4a569c0c 75 } while (u64_stats_fetch_retry(&s->syncp, start));
cd67cd5e
JA
76 sum->conns += conns;
77 sum->inpkts += inpkts;
78 sum->outpkts += outpkts;
b17fc996
HS
79 sum->inbytes += inbytes;
80 sum->outbytes += outbytes;
81 } else {
d1ee4fea 82 add = true;
b17fc996 83 do {
4a569c0c 84 start = u64_stats_fetch_begin(&s->syncp);
cd67cd5e
JA
85 sum->conns = s->cnt.conns;
86 sum->inpkts = s->cnt.inpkts;
87 sum->outpkts = s->cnt.outpkts;
88 sum->inbytes = s->cnt.inbytes;
89 sum->outbytes = s->cnt.outbytes;
4a569c0c 90 } while (u64_stats_fetch_retry(&s->syncp, start));
b17fc996
HS
91 }
92 }
93}
94
95
8ef81c65 96static void estimation_timer(struct timer_list *t)
1da177e4
LT
97{
98 struct ip_vs_estimator *e;
99 struct ip_vs_stats *s;
cd67cd5e 100 u64 rate;
8ef81c65 101 struct netns_ipvs *ipvs = from_timer(ipvs, t, est_timer);
1da177e4 102
29c2026f
HS
103 spin_lock(&ipvs->est_lock);
104 list_for_each_entry(e, &ipvs->est_list, list) {
3a14a313 105 s = container_of(e, struct ip_vs_stats, est);
1da177e4
LT
106
107 spin_lock(&s->lock);
cd67cd5e 108 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
1da177e4
LT
109
110 /* scaled by 2^10, but divided 2 seconds */
cd67cd5e
JA
111 rate = (s->kstats.conns - e->last_conns) << 9;
112 e->last_conns = s->kstats.conns;
113 e->cps += ((s64)rate - (s64)e->cps) >> 2;
114
115 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
116 e->last_inpkts = s->kstats.inpkts;
117 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
118
119 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
120 e->last_outpkts = s->kstats.outpkts;
121 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
122
123 /* scaled by 2^5, but divided 2 seconds */
124 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
125 e->last_inbytes = s->kstats.inbytes;
126 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
127
128 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
129 e->last_outbytes = s->kstats.outbytes;
130 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
1da177e4
LT
131 spin_unlock(&s->lock);
132 }
29c2026f
HS
133 spin_unlock(&ipvs->est_lock);
134 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
1da177e4
LT
135}
136
0f34d54b 137void ip_vs_start_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
1da177e4 138{
3a14a313 139 struct ip_vs_estimator *est = &stats->est;
1da177e4 140
3a14a313 141 INIT_LIST_HEAD(&est->list);
1da177e4 142
29c2026f
HS
143 spin_lock_bh(&ipvs->est_lock);
144 list_add(&est->list, &ipvs->est_list);
145 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
146}
147
0f34d54b 148void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
1da177e4 149{
3a14a313
SW
150 struct ip_vs_estimator *est = &stats->est;
151
29c2026f 152 spin_lock_bh(&ipvs->est_lock);
3a14a313 153 list_del(&est->list);
29c2026f 154 spin_unlock_bh(&ipvs->est_lock);
1da177e4
LT
155}
156
157void ip_vs_zero_estimator(struct ip_vs_stats *stats)
158{
3a14a313 159 struct ip_vs_estimator *est = &stats->est;
cd67cd5e 160 struct ip_vs_kstats *k = &stats->kstats;
55a3d4e1
JA
161
162 /* reset counters, caller must hold the stats->lock lock */
cd67cd5e
JA
163 est->last_inbytes = k->inbytes;
164 est->last_outbytes = k->outbytes;
165 est->last_conns = k->conns;
166 est->last_inpkts = k->inpkts;
167 est->last_outpkts = k->outpkts;
3a14a313
SW
168 est->cps = 0;
169 est->inpps = 0;
170 est->outpps = 0;
171 est->inbps = 0;
172 est->outbps = 0;
1da177e4 173}
a919cf4b 174
ea9f22cc 175/* Get decoded rates */
cd67cd5e 176void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
ea9f22cc
JA
177{
178 struct ip_vs_estimator *e = &stats->est;
179
180 dst->cps = (e->cps + 0x1FF) >> 10;
181 dst->inpps = (e->inpps + 0x1FF) >> 10;
182 dst->outpps = (e->outpps + 0x1FF) >> 10;
183 dst->inbps = (e->inbps + 0xF) >> 5;
184 dst->outbps = (e->outbps + 0xF) >> 5;
185}
186
a4dd0360 187int __net_init ip_vs_estimator_net_init(struct netns_ipvs *ipvs)
61b1ab45 188{
29c2026f
HS
189 INIT_LIST_HEAD(&ipvs->est_list);
190 spin_lock_init(&ipvs->est_lock);
8ef81c65 191 timer_setup(&ipvs->est_timer, estimation_timer, 0);
29c2026f 192 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
61b1ab45
HS
193 return 0;
194}
195
a4dd0360 196void __net_exit ip_vs_estimator_net_cleanup(struct netns_ipvs *ipvs)
29c2026f 197{
a4dd0360 198 del_timer_sync(&ipvs->est_timer);
29c2026f 199}