blob: 702b53ca937ccc4277c8dfee736616bb018772f3 [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 *
11 * Changes:
12 *
13 */
Hannes Eder9aada7a2009-07-30 14:29:44 -070014
15#define KMSG_COMPONENT "IPVS"
16#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020019#include <linux/jiffies.h>
20#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/types.h>
Adrian Bunk4ffd2e42006-01-05 12:14:43 -080022#include <linux/interrupt.h>
Pavel Emelyanov90754f82008-01-12 02:33:50 -080023#include <linux/sysctl.h>
Sven Wegener3a14a3132008-08-10 18:24:41 +000024#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include <net/ip_vs.h>
27
28/*
29 This code is to estimate rate in a shorter interval (such as 8
30 seconds) for virtual services and real servers. For measure rate in a
31 long interval, it is easy to implement a user level daemon which
32 periodically reads those statistical counters and measure rate.
33
34 Currently, the measurement is activated by slow timer handler. Hope
35 this measurement will not introduce too much load.
36
37 We measure rate during the last 8 seconds every 2 seconds:
38
39 avgrate = avgrate*(1-W) + rate*W
40
41 where W = 2^(-2)
42
43 NOTES.
44
45 * The stored value for average bps is scaled by 2^5, so that maximal
46 rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
47
48 * A lot code is taken from net/sched/estimator.c
49 */
50
51
Sven Wegener3a14a3132008-08-10 18:24:41 +000052static void estimation_timer(unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Sven Wegener3a14a3132008-08-10 18:24:41 +000054static LIST_HEAD(est_list);
55static DEFINE_SPINLOCK(est_lock);
56static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58static void estimation_timer(unsigned long arg)
59{
60 struct ip_vs_estimator *e;
61 struct ip_vs_stats *s;
62 u32 n_conns;
63 u32 n_inpkts, n_outpkts;
64 u64 n_inbytes, n_outbytes;
65 u32 rate;
66
Sven Wegener3a14a3132008-08-10 18:24:41 +000067 spin_lock(&est_lock);
68 list_for_each_entry(e, &est_list, list) {
69 s = container_of(e, struct ip_vs_stats, est);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 spin_lock(&s->lock);
Sven Wegenere9c0ce22008-09-08 13:39:04 +020072 n_conns = s->ustats.conns;
73 n_inpkts = s->ustats.inpkts;
74 n_outpkts = s->ustats.outpkts;
75 n_inbytes = s->ustats.inbytes;
76 n_outbytes = s->ustats.outbytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78 /* scaled by 2^10, but divided 2 seconds */
79 rate = (n_conns - e->last_conns)<<9;
80 e->last_conns = n_conns;
81 e->cps += ((long)rate - (long)e->cps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020082 s->ustats.cps = (e->cps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 rate = (n_inpkts - e->last_inpkts)<<9;
85 e->last_inpkts = n_inpkts;
86 e->inpps += ((long)rate - (long)e->inpps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020087 s->ustats.inpps = (e->inpps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89 rate = (n_outpkts - e->last_outpkts)<<9;
90 e->last_outpkts = n_outpkts;
91 e->outpps += ((long)rate - (long)e->outpps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020092 s->ustats.outpps = (e->outpps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94 rate = (n_inbytes - e->last_inbytes)<<4;
95 e->last_inbytes = n_inbytes;
96 e->inbps += ((long)rate - (long)e->inbps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020097 s->ustats.inbps = (e->inbps+0xF)>>5;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99 rate = (n_outbytes - e->last_outbytes)<<4;
100 e->last_outbytes = n_outbytes;
101 e->outbps += ((long)rate - (long)e->outbps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200102 s->ustats.outbps = (e->outbps+0xF)>>5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 spin_unlock(&s->lock);
104 }
Sven Wegener3a14a3132008-08-10 18:24:41 +0000105 spin_unlock(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 mod_timer(&est_timer, jiffies + 2*HZ);
107}
108
Sven Wegener3a14a3132008-08-10 18:24:41 +0000109void ip_vs_new_estimator(struct ip_vs_stats *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000111 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Sven Wegener3a14a3132008-08-10 18:24:41 +0000113 INIT_LIST_HEAD(&est->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200115 est->last_conns = stats->ustats.conns;
116 est->cps = stats->ustats.cps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200118 est->last_inpkts = stats->ustats.inpkts;
119 est->inpps = stats->ustats.inpps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200121 est->last_outpkts = stats->ustats.outpkts;
122 est->outpps = stats->ustats.outpps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200124 est->last_inbytes = stats->ustats.inbytes;
125 est->inbps = stats->ustats.inbps<<5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200127 est->last_outbytes = stats->ustats.outbytes;
128 est->outbps = stats->ustats.outbps<<5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Sven Wegener3a14a3132008-08-10 18:24:41 +0000130 spin_lock_bh(&est_lock);
Sven Wegener3a14a3132008-08-10 18:24:41 +0000131 list_add(&est->list, &est_list);
132 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
135void ip_vs_kill_estimator(struct ip_vs_stats *stats)
136{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000137 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Sven Wegener3a14a3132008-08-10 18:24:41 +0000139 spin_lock_bh(&est_lock);
140 list_del(&est->list);
Sven Wegener3a14a3132008-08-10 18:24:41 +0000141 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
144void ip_vs_zero_estimator(struct ip_vs_stats *stats)
145{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000146 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Sven Wegener3a14a3132008-08-10 18:24:41 +0000148 /* set counters zero, caller must hold the stats->lock lock */
149 est->last_inbytes = 0;
150 est->last_outbytes = 0;
151 est->last_conns = 0;
152 est->last_inpkts = 0;
153 est->last_outpkts = 0;
154 est->cps = 0;
155 est->inpps = 0;
156 est->outpps = 0;
157 est->inbps = 0;
158 est->outbps = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159}
Sven Wegenera919cf42008-08-14 00:47:16 +0200160
161int __init ip_vs_estimator_init(void)
162{
163 mod_timer(&est_timer, jiffies + 2 * HZ);
164 return 0;
165}
166
167void ip_vs_estimator_cleanup(void)
168{
169 del_timer_sync(&est_timer);
170}