blob: 457c6c193e1332ab803b6f381f1329f85f1ebdf6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ip_vs_est.c: simple rate estimator for IPVS
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * 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 *
Hans Schillstrom29c20262011-01-03 14:44:54 +010011 * 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Hannes Eder9aada7a2009-07-30 14:29:44 -070018
19#define KMSG_COMPONENT "IPVS"
20#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/kernel.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020023#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/types.h>
Adrian Bunk4ffd2e42006-01-05 12:14:43 -080025#include <linux/interrupt.h>
Pavel Emelyanov90754f82008-01-12 02:33:50 -080026#include <linux/sysctl.h>
Sven Wegener3a14a3132008-08-10 18:24:41 +000027#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
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
Julian Anastasovcd67cd52015-02-06 09:44:44 +020048 * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10.
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Julian Anastasovcd67cd52015-02-06 09:44:44 +020050 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 */
55
56
Hans Schillstromb17fc992011-01-03 14:44:56 +010057/*
58 * Make a summary from each cpu
59 */
Julian Anastasovcd67cd52015-02-06 09:44:44 +020060static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
Julian Anastasovb962abd2013-03-09 23:25:08 +020061 struct ip_vs_cpu_stats __percpu *stats)
Hans Schillstromb17fc992011-01-03 14:44:56 +010062{
63 int i;
Julian Anastasovd1ee4fe2013-09-12 11:21:10 +030064 bool add = false;
Hans Schillstromb17fc992011-01-03 14:44:56 +010065
66 for_each_possible_cpu(i) {
67 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
68 unsigned int start;
Julian Anastasovcd67cd52015-02-06 09:44:44 +020069 u64 conns, inpkts, outpkts, inbytes, outbytes;
70
Julian Anastasovd1ee4fe2013-09-12 11:21:10 +030071 if (add) {
Hans Schillstromb17fc992011-01-03 14:44:56 +010072 do {
Julian Anastasov4a569c02011-03-04 12:28:20 +020073 start = u64_stats_fetch_begin(&s->syncp);
Julian Anastasovcd67cd52015-02-06 09:44:44 +020074 conns = s->cnt.conns;
75 inpkts = s->cnt.inpkts;
76 outpkts = s->cnt.outpkts;
77 inbytes = s->cnt.inbytes;
78 outbytes = s->cnt.outbytes;
Julian Anastasov4a569c02011-03-04 12:28:20 +020079 } while (u64_stats_fetch_retry(&s->syncp, start));
Julian Anastasovcd67cd52015-02-06 09:44:44 +020080 sum->conns += conns;
81 sum->inpkts += inpkts;
82 sum->outpkts += outpkts;
Hans Schillstromb17fc992011-01-03 14:44:56 +010083 sum->inbytes += inbytes;
84 sum->outbytes += outbytes;
85 } else {
Julian Anastasovd1ee4fe2013-09-12 11:21:10 +030086 add = true;
Hans Schillstromb17fc992011-01-03 14:44:56 +010087 do {
Julian Anastasov4a569c02011-03-04 12:28:20 +020088 start = u64_stats_fetch_begin(&s->syncp);
Julian Anastasovcd67cd52015-02-06 09:44:44 +020089 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;
Julian Anastasov4a569c02011-03-04 12:28:20 +020094 } while (u64_stats_fetch_retry(&s->syncp, start));
Hans Schillstromb17fc992011-01-03 14:44:56 +010095 }
96 }
97}
98
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static void estimation_timer(unsigned long arg)
101{
102 struct ip_vs_estimator *e;
103 struct ip_vs_stats *s;
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200104 u64 rate;
Eric W. Biederman70a131a2015-09-21 13:02:27 -0500105 struct netns_ipvs *ipvs = (struct netns_ipvs *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Hans Schillstrom29c20262011-01-03 14:44:54 +0100107 spin_lock(&ipvs->est_lock);
108 list_for_each_entry(e, &ipvs->est_list, list) {
Sven Wegener3a14a3132008-08-10 18:24:41 +0000109 s = container_of(e, struct ip_vs_stats, est);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 spin_lock(&s->lock);
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200112 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114 /* scaled by 2^10, but divided 2 seconds */
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200115 rate = (s->kstats.conns - e->last_conns) << 9;
116 e->last_conns = s->kstats.conns;
117 e->cps += ((s64)rate - (s64)e->cps) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200119 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
120 e->last_inpkts = s->kstats.inpkts;
121 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200123 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
124 e->last_outpkts = s->kstats.outpkts;
125 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200127 /* scaled by 2^5, but divided 2 seconds */
128 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
129 e->last_inbytes = s->kstats.inbytes;
130 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200132 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
133 e->last_outbytes = s->kstats.outbytes;
134 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 spin_unlock(&s->lock);
136 }
Hans Schillstrom29c20262011-01-03 14:44:54 +0100137 spin_unlock(&ipvs->est_lock);
138 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Eric W. Biederman0f34d542015-09-21 13:02:23 -0500141void ip_vs_start_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000143 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Sven Wegener3a14a3132008-08-10 18:24:41 +0000145 INIT_LIST_HEAD(&est->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Hans Schillstrom29c20262011-01-03 14:44:54 +0100147 spin_lock_bh(&ipvs->est_lock);
148 list_add(&est->list, &ipvs->est_list);
149 spin_unlock_bh(&ipvs->est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150}
151
Eric W. Biederman0f34d542015-09-21 13:02:23 -0500152void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000154 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Hans Schillstrom29c20262011-01-03 14:44:54 +0100156 spin_lock_bh(&ipvs->est_lock);
Sven Wegener3a14a3132008-08-10 18:24:41 +0000157 list_del(&est->list);
Hans Schillstrom29c20262011-01-03 14:44:54 +0100158 spin_unlock_bh(&ipvs->est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159}
160
161void ip_vs_zero_estimator(struct ip_vs_stats *stats)
162{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000163 struct ip_vs_estimator *est = &stats->est;
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200164 struct ip_vs_kstats *k = &stats->kstats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Julian Anastasov55a3d4e2011-03-14 01:37:49 +0200166 /* reset counters, caller must hold the stats->lock lock */
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200167 est->last_inbytes = k->inbytes;
168 est->last_outbytes = k->outbytes;
169 est->last_conns = k->conns;
170 est->last_inpkts = k->inpkts;
171 est->last_outpkts = k->outpkts;
Sven Wegener3a14a3132008-08-10 18:24:41 +0000172 est->cps = 0;
173 est->inpps = 0;
174 est->outpps = 0;
175 est->inbps = 0;
176 est->outbps = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
Sven Wegenera919cf42008-08-14 00:47:16 +0200178
Julian Anastasovea9f22c2011-03-14 01:41:54 +0200179/* Get decoded rates */
Julian Anastasovcd67cd52015-02-06 09:44:44 +0200180void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
Julian Anastasovea9f22c2011-03-14 01:41:54 +0200181{
182 struct ip_vs_estimator *e = &stats->est;
183
184 dst->cps = (e->cps + 0x1FF) >> 10;
185 dst->inpps = (e->inpps + 0x1FF) >> 10;
186 dst->outpps = (e->outpps + 0x1FF) >> 10;
187 dst->inbps = (e->inbps + 0xF) >> 5;
188 dst->outbps = (e->outbps + 0xF) >> 5;
189}
190
Eric W. Biedermana4dd0362015-09-21 13:02:28 -0500191int __net_init ip_vs_estimator_net_init(struct netns_ipvs *ipvs)
Hans Schillstrom61b1ab42011-01-03 14:44:42 +0100192{
Hans Schillstrom29c20262011-01-03 14:44:54 +0100193 INIT_LIST_HEAD(&ipvs->est_list);
194 spin_lock_init(&ipvs->est_lock);
Eric W. Biederman70a131a2015-09-21 13:02:27 -0500195 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)ipvs);
Hans Schillstrom29c20262011-01-03 14:44:54 +0100196 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
Hans Schillstrom61b1ab42011-01-03 14:44:42 +0100197 return 0;
198}
199
Eric W. Biedermana4dd0362015-09-21 13:02:28 -0500200void __net_exit ip_vs_estimator_net_cleanup(struct netns_ipvs *ipvs)
Hans Schillstrom29c20262011-01-03 14:44:54 +0100201{
Eric W. Biedermana4dd0362015-09-21 13:02:28 -0500202 del_timer_sync(&ipvs->est_timer);
Hans Schillstrom29c20262011-01-03 14:44:54 +0100203}