blob: 2eb2860dabb57cc24d1c5bf0c0cd117603f1a0e5 [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 */
14#include <linux/kernel.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020015#include <linux/jiffies.h>
16#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/types.h>
Adrian Bunk4ffd2e42006-01-05 12:14:43 -080018#include <linux/interrupt.h>
Pavel Emelyanov90754f82008-01-12 02:33:50 -080019#include <linux/sysctl.h>
Sven Wegener3a14a3132008-08-10 18:24:41 +000020#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22#include <net/ip_vs.h>
23
24/*
25 This code is to estimate rate in a shorter interval (such as 8
26 seconds) for virtual services and real servers. For measure rate in a
27 long interval, it is easy to implement a user level daemon which
28 periodically reads those statistical counters and measure rate.
29
30 Currently, the measurement is activated by slow timer handler. Hope
31 this measurement will not introduce too much load.
32
33 We measure rate during the last 8 seconds every 2 seconds:
34
35 avgrate = avgrate*(1-W) + rate*W
36
37 where W = 2^(-2)
38
39 NOTES.
40
41 * The stored value for average bps is scaled by 2^5, so that maximal
42 rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
43
44 * A lot code is taken from net/sched/estimator.c
45 */
46
47
Sven Wegener3a14a3132008-08-10 18:24:41 +000048static void estimation_timer(unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Sven Wegener3a14a3132008-08-10 18:24:41 +000050static LIST_HEAD(est_list);
51static DEFINE_SPINLOCK(est_lock);
52static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54static void estimation_timer(unsigned long arg)
55{
56 struct ip_vs_estimator *e;
57 struct ip_vs_stats *s;
58 u32 n_conns;
59 u32 n_inpkts, n_outpkts;
60 u64 n_inbytes, n_outbytes;
61 u32 rate;
62
Sven Wegener3a14a3132008-08-10 18:24:41 +000063 spin_lock(&est_lock);
64 list_for_each_entry(e, &est_list, list) {
65 s = container_of(e, struct ip_vs_stats, est);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67 spin_lock(&s->lock);
Sven Wegenere9c0ce22008-09-08 13:39:04 +020068 n_conns = s->ustats.conns;
69 n_inpkts = s->ustats.inpkts;
70 n_outpkts = s->ustats.outpkts;
71 n_inbytes = s->ustats.inbytes;
72 n_outbytes = s->ustats.outbytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74 /* scaled by 2^10, but divided 2 seconds */
75 rate = (n_conns - e->last_conns)<<9;
76 e->last_conns = n_conns;
77 e->cps += ((long)rate - (long)e->cps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020078 s->ustats.cps = (e->cps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 rate = (n_inpkts - e->last_inpkts)<<9;
81 e->last_inpkts = n_inpkts;
82 e->inpps += ((long)rate - (long)e->inpps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020083 s->ustats.inpps = (e->inpps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85 rate = (n_outpkts - e->last_outpkts)<<9;
86 e->last_outpkts = n_outpkts;
87 e->outpps += ((long)rate - (long)e->outpps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020088 s->ustats.outpps = (e->outpps+0x1FF)>>10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 rate = (n_inbytes - e->last_inbytes)<<4;
91 e->last_inbytes = n_inbytes;
92 e->inbps += ((long)rate - (long)e->inbps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020093 s->ustats.inbps = (e->inbps+0xF)>>5;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95 rate = (n_outbytes - e->last_outbytes)<<4;
96 e->last_outbytes = n_outbytes;
97 e->outbps += ((long)rate - (long)e->outbps)>>2;
Sven Wegenere9c0ce22008-09-08 13:39:04 +020098 s->ustats.outbps = (e->outbps+0xF)>>5;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 spin_unlock(&s->lock);
100 }
Sven Wegener3a14a3132008-08-10 18:24:41 +0000101 spin_unlock(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 mod_timer(&est_timer, jiffies + 2*HZ);
103}
104
Sven Wegener3a14a3132008-08-10 18:24:41 +0000105void ip_vs_new_estimator(struct ip_vs_stats *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000107 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Sven Wegener3a14a3132008-08-10 18:24:41 +0000109 INIT_LIST_HEAD(&est->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200111 est->last_conns = stats->ustats.conns;
112 est->cps = stats->ustats.cps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200114 est->last_inpkts = stats->ustats.inpkts;
115 est->inpps = stats->ustats.inpps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200117 est->last_outpkts = stats->ustats.outpkts;
118 est->outpps = stats->ustats.outpps<<10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200120 est->last_inbytes = stats->ustats.inbytes;
121 est->inbps = stats->ustats.inbps<<5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Sven Wegenere9c0ce22008-09-08 13:39:04 +0200123 est->last_outbytes = stats->ustats.outbytes;
124 est->outbps = stats->ustats.outbps<<5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Sven Wegener3a14a3132008-08-10 18:24:41 +0000126 spin_lock_bh(&est_lock);
Sven Wegener3a14a3132008-08-10 18:24:41 +0000127 list_add(&est->list, &est_list);
128 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129}
130
131void ip_vs_kill_estimator(struct ip_vs_stats *stats)
132{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000133 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Sven Wegener3a14a3132008-08-10 18:24:41 +0000135 spin_lock_bh(&est_lock);
136 list_del(&est->list);
Sven Wegener3a14a3132008-08-10 18:24:41 +0000137 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
140void ip_vs_zero_estimator(struct ip_vs_stats *stats)
141{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000142 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Sven Wegener3a14a3132008-08-10 18:24:41 +0000144 /* set counters zero, caller must hold the stats->lock lock */
145 est->last_inbytes = 0;
146 est->last_outbytes = 0;
147 est->last_conns = 0;
148 est->last_inpkts = 0;
149 est->last_outpkts = 0;
150 est->cps = 0;
151 est->inpps = 0;
152 est->outpps = 0;
153 est->inbps = 0;
154 est->outbps = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
Sven Wegenera919cf42008-08-14 00:47:16 +0200156
157int __init ip_vs_estimator_init(void)
158{
159 mod_timer(&est_timer, jiffies + 2 * HZ);
160 return 0;
161}
162
163void ip_vs_estimator_cleanup(void)
164{
165 del_timer_sync(&est_timer);
166}