blob: 8729231fc005a27460a8aa319b19e235f6ccdba3 [file] [log] [blame]
Alexander Afanasyev6f95e702012-10-31 16:27:31 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2011 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19 */
20
Alexander Afanasyev0c395372014-12-20 15:54:02 -080021#include "ndn-limits-rate.hpp"
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070022
23#include "ns3/log.h"
24#include "ns3/simulator.h"
25#include "ns3/random-variable.h"
Alexander Afanasyev0c395372014-12-20 15:54:02 -080026#include "ns3/ndn-face.hpp"
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070027#include "ns3/node.h"
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070028
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080029NS_LOG_COMPONENT_DEFINE("ndn.Limits.Rate");
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070030
31namespace ns3 {
32namespace ndn {
33
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080034NS_OBJECT_ENSURE_REGISTERED(LimitsRate);
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070035
36TypeId
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080037LimitsRate::GetTypeId()
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070038{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080039 static TypeId tid =
40 TypeId("ns3::ndn::Limits::Rate")
41 .SetGroupName("Ndn")
42 .SetParent<Limits>()
43 .AddConstructor<LimitsRate>()
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -080044
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080045 .AddAttribute("RandomizeLeak", "Randomize start time for token bucket leakage. May be "
46 "helpful to prevent leak synchronizations",
47 TimeValue(Seconds(0.001)),
48 MakeTimeAccessor(&LimitsRate::m_leakRandomizationInteral), MakeTimeChecker())
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -080049
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070050 ;
51 return tid;
52}
53
54void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080055LimitsRate::NotifyNewAggregate()
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070056{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080057 super::NotifyNewAggregate();
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070058
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080059 if (!m_isLeakScheduled) {
60 if (GetObject<Face>() != 0) {
61 NS_ASSERT_MSG(GetObject<Face>()->GetNode() != 0, "Node object should exist on the face");
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -080062
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080063 m_isLeakScheduled = true;
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -080064
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080065 if (!m_leakRandomizationInteral.IsZero()) {
66 UniformVariable r(0.0, m_leakRandomizationInteral.ToDouble(Time::S));
67 Simulator::ScheduleWithContext(GetObject<Face>()->GetNode()->GetId(), Seconds(r.GetValue()),
68 &LimitsRate::LeakBucket, this, 0.0);
69 }
70 else {
71 Simulator::ScheduleWithContext(GetObject<Face>()->GetNode()->GetId(), Seconds(0),
72 &LimitsRate::LeakBucket, this, 0.0);
73 }
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070074 }
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080075 }
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070076}
77
Alexander Afanasyevccd5bb42012-10-31 17:27:49 -070078void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080079LimitsRate::SetLimits(double rate, double delay)
Alexander Afanasyevccd5bb42012-10-31 17:27:49 -070080{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080081 super::SetLimits(rate, delay);
Alexander Afanasyevccd5bb42012-10-31 17:27:49 -070082
83 // maximum allowed burst
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080084 m_bucketMax = GetMaxRate() * GetMaxDelay();
Alexander Afanasyevccd5bb42012-10-31 17:27:49 -070085
86 // amount of packets allowed every second (leak rate)
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080087 m_bucketLeak = GetMaxRate();
Alexander Afanasyevccd5bb42012-10-31 17:27:49 -070088}
89
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -070090void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080091LimitsRate::UpdateCurrentLimit(double limit)
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070092{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080093 NS_ASSERT_MSG(limit >= 0.0, "Limit should be greater or equal to zero");
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -080094
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -080095 m_bucketLeak = std::min(limit, GetMaxRate());
96 m_bucketMax = m_bucketLeak * GetMaxDelay();
Alexander Afanasyev6f95e702012-10-31 16:27:31 -070097}
98
99bool
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800100LimitsRate::IsBelowLimit()
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700101{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800102 if (!IsEnabled())
103 return true;
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700104
105 return (m_bucketMax - m_bucket >= 1.0);
106}
107
108void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800109LimitsRate::BorrowLimit()
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700110{
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800111 if (!IsEnabled())
112 return;
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700113
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800114 NS_ASSERT_MSG(m_bucketMax - m_bucket >= 1.0,
115 "Should not be possible, unless we IsBelowLimit was not checked correctly");
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -0800116 m_bucket += 1;
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700117}
118
119void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800120LimitsRate::ReturnLimit()
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700121{
122 // do nothing
123}
124
125void
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800126LimitsRate::LeakBucket(double interval)
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700127{
128 const double leak = m_bucketLeak * interval;
129
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -0800130#ifdef NS3_LOG_ENABLE
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800131 if (m_bucket > 1) {
132 NS_LOG_DEBUG("Leak from " << m_bucket << " to " << std::max(0.0, m_bucket - leak));
133 }
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -0700134#endif
Alexander Afanasyev08ab5722012-11-06 17:22:25 -0800135
136 double bucketOld = m_bucket;
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -0800137
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800138 m_bucket = std::max(0.0, m_bucket - leak);
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -0700139
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800140 // calculate interval so next time we will leak by 1.001, unless such interval would be more than
141 // 1 second
Alexander Afanasyev7e4235a2012-10-31 16:58:44 -0700142 double newInterval = 1.0;
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800143 if (m_bucketLeak > 1.0) {
144 newInterval = 1.001 / m_bucketLeak;
145 }
Alexander Afanasyev08ab5722012-11-06 17:22:25 -0800146
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800147 if (m_bucketMax - bucketOld < 1.0
148 && m_bucketMax - m_bucket >= 1.0) // limit number of times this stuff is called
149 {
150 this->FireAvailableSlotCallback();
151 }
Alexander Afanasyevdc115ef2013-02-13 12:06:55 -0800152
Alexander Afanasyevbe55cf62014-12-20 17:51:09 -0800153 Simulator::Schedule(Seconds(newInterval), &LimitsRate::LeakBucket, this, newInterval);
Alexander Afanasyev6f95e702012-10-31 16:27:31 -0700154}
155
156} // namespace ndn
157} // namespace ns3