Skip to content

Commit ad00a23

Browse files
committed
Add RED AQM.
1 parent 2ba9a92 commit ad00a23

File tree

6 files changed

+160
-6
lines changed

6 files changed

+160
-6
lines changed

src/frontend/linkshell.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "drop_head_packet_queue.hh"
88
#include "codel_packet_queue.hh"
99
#include "pie_packet_queue.hh"
10+
#include "red_packet_queue.hh"
1011
#include "link_queue.hh"
1112
#include "packetshell.cc"
1213

@@ -44,6 +45,8 @@ unique_ptr<AbstractPacketQueue> get_packet_queue( const string & type, const str
4445
return unique_ptr<AbstractPacketQueue>( new CODELPacketQueue( args ) );
4546
} else if ( type == "pie" ) {
4647
return unique_ptr<AbstractPacketQueue>( new PIEPacketQueue( args ) );
48+
} else if ( type == "red" ) {
49+
return unique_ptr<AbstractPacketQueue>( new REDPacketQueue( args ) );
4750
} else {
4851
cerr << "Unknown queue type: " << type << endl;
4952
}
@@ -96,8 +99,8 @@ int main( int argc, char *argv[] )
9699
{ "meter-downlink-delay", no_argument, nullptr, 'y' },
97100
{ "meter-all", no_argument, nullptr, 'z' },
98101
{ "uplink-queue", required_argument, nullptr, 'q' },
99-
{ "downlink-queue", required_argument, nullptr, 'w' },
100102
{ "uplink-queue-args", required_argument, nullptr, 'a' },
103+
{ "downlink-queue", required_argument, nullptr, 'w' },
101104
{ "downlink-queue-args", required_argument, nullptr, 'b' },
102105
{ 0, 0, nullptr, 0 }
103106
};

src/packet/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ libpacket_a_SOURCES = packetshell.hh packetshell.cc queued_packet.hh \
77
abstract_packet_queue.hh dropping_packet_queue.hh dropping_packet_queue.cc infinite_packet_queue.hh \
88
drop_tail_packet_queue.hh drop_head_packet_queue.hh \
99
codel_packet_queue.cc codel_packet_queue.hh \
10+
red_packet_queue.cc red_packet_queue.hh \
1011
pie_packet_queue.cc pie_packet_queue.hh \
1112
bindworkaround.hh

src/packet/dropping_packet_queue.cc

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ string DroppingPacketQueue::to_string( void ) const
9999
return ret;
100100
}
101101

102-
unsigned int DroppingPacketQueue::get_arg( const string & args, const string & name )
102+
string DroppingPacketQueue::parse_number_arg(const string & args, const string & name, bool isfloat)
103103
{
104104
auto offset = args.find( name );
105105
if ( offset == string::npos ) {
106-
return 0; /* default value */
106+
return ""; /* default value */
107107
} else {
108108
/* extract the value */
109109

@@ -112,21 +112,52 @@ unsigned int DroppingPacketQueue::get_arg( const string & args, const string & n
112112

113113
/* make sure next char is "=" */
114114
if ( args.substr( offset, 1 ) != "=" ) {
115-
throw runtime_error( "could not parse queue arguments: " + args );
115+
throw runtime_error( "could not parse queue arguments: " + args);
116116
}
117117

118118
/* advance by length of "=" */
119119
offset++;
120120

121-
/* find the first non-digit character */
122-
auto offset2 = args.substr( offset ).find_first_not_of( "0123456789" );
121+
/* find the first non-valid character */
122+
string validchars;
123+
if (isfloat) {
124+
validchars = "0123456789.";
125+
} else {
126+
validchars = "0123456789";
127+
}
128+
auto offset2 = args.substr( offset ).find_first_not_of( validchars );
123129

124130
auto digit_string = args.substr( offset ).substr( 0, offset2 );
125131

126132
if ( digit_string.empty() ) {
127133
throw runtime_error( "could not parse queue arguments: " + args );
128134
}
135+
return digit_string;
136+
}
137+
}
138+
139+
unsigned int DroppingPacketQueue::get_arg( const string & args, const string & name)
140+
{
141+
auto offset = args.find( name );
142+
if ( offset == string::npos ) {
143+
return 0; /* default value */
144+
} else {
145+
auto digit_string = parse_number_arg(args, name, false);
129146

130147
return myatoi( digit_string );
131148
}
132149
}
150+
151+
double DroppingPacketQueue::get_float_arg( const string & args, const string & name)
152+
{
153+
auto offset = args.find( name );
154+
if ( offset == string::npos ) {
155+
return 0; /* default value */
156+
} else {
157+
auto digit_string = parse_number_arg(args, name, true);
158+
return myatof( digit_string );
159+
}
160+
161+
}
162+
163+

src/packet/dropping_packet_queue.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ public:
4444

4545
std::string to_string( void ) const override;
4646

47+
static std::string parse_number_arg(const std::string & args, const std::string & name, bool isfloat);
4748
static unsigned int get_arg( const std::string & args, const std::string & name );
49+
static double get_float_arg( const std::string & args, const std::string & name );
4850
};
4951

5052
#endif /* DROPPING_PACKET_QUEUE_HH */

src/packet/red_packet_queue.cc

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "red_packet_queue.hh"
2+
#include <algorithm>
3+
#include "timestamp.hh"
4+
5+
using namespace std;
6+
7+
REDPacketQueue::REDPacketQueue( const string & args)
8+
: DroppingPacketQueue(args),
9+
wq_(get_float_arg(args, "wq")),
10+
min_thresh_(get_float_arg(args, "minthresh")),
11+
max_thresh_(get_float_arg(args, "maxthresh")),
12+
time_at_zero_q_(0)
13+
{
14+
if ( wq_ == 0.0 || min_thresh_ == 0.0 || max_thresh_ == 0.0 ) {
15+
throw runtime_error( "RED queue must have wq, minthresh, and maxthresh arguments." );
16+
}
17+
18+
}
19+
20+
unsigned int REDPacketQueue::max_queue_depth_packets (void ) const {
21+
if (packet_limit_) {
22+
return packet_limit_;
23+
} else if (byte_limit_ ) {
24+
return byte_limit_ / PACKET_SIZE;
25+
} else {
26+
throw runtime_error( "No queue limit provided");
27+
}
28+
}
29+
30+
QueuedPacket REDPacketQueue::dequeue( void )
31+
{
32+
auto packet = DroppingPacketQueue::dequeue();
33+
if (size_packets() == 0) {
34+
time_at_zero_q_ = timestamp();
35+
}
36+
37+
return packet;
38+
}
39+
40+
void REDPacketQueue::enqueue( QueuedPacket && p )
41+
{
42+
int s = 4;
43+
auto instantaneous_queue_size = size_packets();
44+
45+
/* If the queue is empty, decay the weighted average by
46+
* the amount of time that the queue has been
47+
* empty. */
48+
if (size_packets() == 0) {
49+
weighted_average_ = powf((1 - wq_), (timestamp() - time_at_zero_q_)/s) * weighted_average_;
50+
} else {
51+
weighted_average_ = (instantaneous_queue_size * wq_ ) + (1- wq_) * weighted_average_;
52+
}
53+
54+
auto ratio = (weighted_average_)/max_queue_depth_packets();
55+
std::default_random_engine generator (0);
56+
std::uniform_real_distribution<double> distribution (min_thresh_, max_thresh_);
57+
double threshold = distribution(generator);
58+
if (ratio > max_thresh_) {
59+
ratio = 1;
60+
}
61+
if (ratio < min_thresh_) {
62+
ratio = 0;
63+
}
64+
65+
if ( (threshold > ratio) && good_with( size_bytes() + p.contents.size(),
66+
size_packets() + 1 ) ) {
67+
accept( std::move( p ) );
68+
}
69+
70+
assert( good() );
71+
}

src/packet/red_packet_queue.hh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
#ifndef RED_PACKET_QUEUE_HH
4+
#define RED_PACKET_QUEUE_HH
5+
6+
#include <string>
7+
#include "util.hh"
8+
#include <iostream>
9+
10+
#include <fstream>
11+
#include <memory>
12+
#include <deque>
13+
#include <random>
14+
#include "dropping_packet_queue.hh"
15+
16+
/*
17+
Random Early Detection (RED) AQM Implementation.
18+
See section 3 of https://tools.ietf.org/html/rfc2309#ref-Jacobson88
19+
for a description of the queuing discipline.
20+
j
21+
22+
*/
23+
class REDPacketQueue : public DroppingPacketQueue
24+
{
25+
private:
26+
//Configuration parameters
27+
const static unsigned int PACKET_SIZE = 1504;
28+
double wq_, min_thresh_, max_thresh_;
29+
uint64_t time_at_zero_q_;
30+
31+
const std::string & type( void ) const override
32+
{
33+
static const std::string type_ { "red" };
34+
return type_;
35+
}
36+
37+
double weighted_average_ = 0;
38+
unsigned int max_queue_depth_packets() const;
39+
40+
public:
41+
REDPacketQueue( const std::string & args );
42+
QueuedPacket dequeue( void ) override;
43+
void enqueue( QueuedPacket && p ) override;
44+
};
45+
46+
#endif

0 commit comments

Comments
 (0)