linux/net/netfilter/ipvs/ip_vs_est.c
<<
>>
Prefs
   1/*
   2 * ip_vs_est.c: simple rate estimator for IPVS
   3 *
   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 *
  11 * Changes:
  12 *
  13 */
  14
  15#define KMSG_COMPONENT "IPVS"
  16#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  17
  18#include <linux/kernel.h>
  19#include <linux/jiffies.h>
  20#include <linux/slab.h>
  21#include <linux/types.h>
  22#include <linux/interrupt.h>
  23#include <linux/sysctl.h>
  24#include <linux/list.h>
  25
  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
  52static void estimation_timer(unsigned long arg);
  53
  54static LIST_HEAD(est_list);
  55static DEFINE_SPINLOCK(est_lock);
  56static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
  57
  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
  67        spin_lock(&est_lock);
  68        list_for_each_entry(e, &est_list, list) {
  69                s = container_of(e, struct ip_vs_stats, est);
  70
  71                spin_lock(&s->lock);
  72                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;
  77
  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;
  82                s->ustats.cps = (e->cps+0x1FF)>>10;
  83
  84                rate = (n_inpkts - e->last_inpkts)<<9;
  85                e->last_inpkts = n_inpkts;
  86                e->inpps += ((long)rate - (long)e->inpps)>>2;
  87                s->ustats.inpps = (e->inpps+0x1FF)>>10;
  88
  89                rate = (n_outpkts - e->last_outpkts)<<9;
  90                e->last_outpkts = n_outpkts;
  91                e->outpps += ((long)rate - (long)e->outpps)>>2;
  92                s->ustats.outpps = (e->outpps+0x1FF)>>10;
  93
  94                rate = (n_inbytes - e->last_inbytes)<<4;
  95                e->last_inbytes = n_inbytes;
  96                e->inbps += ((long)rate - (long)e->inbps)>>2;
  97                s->ustats.inbps = (e->inbps+0xF)>>5;
  98
  99                rate = (n_outbytes - e->last_outbytes)<<4;
 100                e->last_outbytes = n_outbytes;
 101                e->outbps += ((long)rate - (long)e->outbps)>>2;
 102                s->ustats.outbps = (e->outbps+0xF)>>5;
 103                spin_unlock(&s->lock);
 104        }
 105        spin_unlock(&est_lock);
 106        mod_timer(&est_timer, jiffies + 2*HZ);
 107}
 108
 109void ip_vs_new_estimator(struct ip_vs_stats *stats)
 110{
 111        struct ip_vs_estimator *est = &stats->est;
 112
 113        INIT_LIST_HEAD(&est->list);
 114
 115        est->last_conns = stats->ustats.conns;
 116        est->cps = stats->ustats.cps<<10;
 117
 118        est->last_inpkts = stats->ustats.inpkts;
 119        est->inpps = stats->ustats.inpps<<10;
 120
 121        est->last_outpkts = stats->ustats.outpkts;
 122        est->outpps = stats->ustats.outpps<<10;
 123
 124        est->last_inbytes = stats->ustats.inbytes;
 125        est->inbps = stats->ustats.inbps<<5;
 126
 127        est->last_outbytes = stats->ustats.outbytes;
 128        est->outbps = stats->ustats.outbps<<5;
 129
 130        spin_lock_bh(&est_lock);
 131        list_add(&est->list, &est_list);
 132        spin_unlock_bh(&est_lock);
 133}
 134
 135void ip_vs_kill_estimator(struct ip_vs_stats *stats)
 136{
 137        struct ip_vs_estimator *est = &stats->est;
 138
 139        spin_lock_bh(&est_lock);
 140        list_del(&est->list);
 141        spin_unlock_bh(&est_lock);
 142}
 143
 144void ip_vs_zero_estimator(struct ip_vs_stats *stats)
 145{
 146        struct ip_vs_estimator *est = &stats->est;
 147
 148        /* 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;
 159}
 160
 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}
 171