[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
A token bucket shaper implementation
Hi,
I'm sending my implementation of a token bucket shapper (files dsshaper.h
and dsshapper.cc). You must include dsshaper.o in Makefile.
I can't explain the difference my implementation and the original tbf
implementation in ns, because I didn't know the ns implementation.
To use it, you must configure 4 parameters (peak rate, burst size,
queue legth and flow id) and insert it between two nodes, as shown
below:
# Function to insert the shaper between two nodes
Simulator instproc insert-shaper {shaper n1 n2} {
$self instvar link_
set sid [$n1 id]
set did [$n2 id]
set templink $link_($sid:$did)
set linktarget [$templink get-target]
$templink set-target $shaper
$shaper target $linktarget
}
#Create two nodes
set n0 [$ns node]
set n1 [$ns node]
#Create the shaper
set shaper [new DSShaper]
$shaper set-peak-rate 500000
$shaper set-burst-size 16000
$shaper set-queue-length 3
$shaper set-fid 1
#Insert the shaper between nodes n0 and n1
$ns insert-shaper $shaper $n0 $n1
Regards
Carlos
---------------------------------------------
Carlos Alberto Kamienski [email protected]
Doutorando em Ciencia da Computacao
Ph.D. Student
Departamento de Informatica - UFPE
---------------------------------------------
On Wed, 10 Nov 1999, Poyuen Cheng wrote:
> Hi,
>
> Sorry to bother you again. I still haven't received your implementation
> of token bucket shaper. Thanks for your help.
>
> Po-Yuen
>
> > -----Original Message-----
> > From: Carlos Alberto Kamienski [SMTP:[email protected]]
> > Sent: Monday, November 08, 1999 3:08 AM
> > To: Poyuen Cheng
> > Cc: '[email protected]'
> > Subject: Re: leaky bucket
> >
> > Hi Po-Yuen
> >
> > I have implemented a shaper (using a token bucket) and I can send it to
> > you if you have interest (it isn't avaiable on-line yet)
> >
> > Carlos
> >
> > ---------------------------------------------
> > Carlos Alberto Kamienski [email protected]
> >
> > Doutorando em Ciencia da Computacao
> > Ph.D. Student
> > Departamento de Informatica - UFPE
> > ---------------------------------------------
> >
> > On Wed, 3 Nov 1999, Poyuen Cheng wrote:
> >
> > > Hi,
> > >
> > > Is there any way to implement the traffic shaping algorithms, such
> > > as leaky bucket or token bucket, on the ns? Thanks,
> > >
> > > Po-Yuen Cheng
> > >
> > >
>
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999, Federal University of Pernambuco - Brazil.
* All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Contributed by Carlos Alberto Kamienski <[email protected]>
*
*/
#ifndef ns_dsshapper_h
#define ns_dsshapper_h
#include "packet.h"
#include "connector.h"
#include "queue.h"
class DSShaper;
class DSShaperHandler : public Handler {
public:
DSShaperHandler(DSShaper *s) : shaper_(s) {}
void handle(Event *e);
private:
DSShaper *shaper_;
};
class DSShaper: public Connector {
private:
int received_packets ;
int sent_packets ;
int shaped_packets ;
int dropped_packets ;
int max_queue_length;
PacketQueue shape_queue;
double peak_ ;
int burst_size_ ;
int curr_bucket_contents ;
int flow_id_;
double last_time ;
bool shape_packet(Packet *p) ;
void schedule_packet(Packet *p) ;
bool in_profile(Packet *p) ;
void update_bucket_contents() ;
void reset_counters();
DSShaperHandler sh_;
public:
DSShaper() ;
void resume();
void recv(Packet *p, Handler *h) ;
int command(int argc, const char*const* argv) ;
} ;
#endif
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999, Federal University of Pernambuco - Brazil.
* All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Carlos Alberto Kamienski <[email protected]>
*
*/
#include <fstream.h>
#include "dsshaper.h"
#include "scheduler.h"
#include "packet.h"
void DSShaperHandler::handle(Event *e)
{
shaper_->resume();
}
static class DSShaperTclClass : public TclClass {
public:
DSShaperTclClass() : TclClass("DSShaper") {}
TclObject* create(int, const char*const*) {
return (new DSShaper);
}
} class_dsshaper ;
DSShaper::DSShaper() : Connector(),
received_packets(0),
sent_packets(0),
shaped_packets(0),
dropped_packets(0),
max_queue_length(0),
flow_id_(0),
last_time(0),
sh_(this)
{
}
void DSShaper::recv(Packet *p, Handler *h)
{
struct hdr_ip *iph = HDR_IP(p) ;
if (iph->fid_ != flow_id_) {
// Just send packets which fid_ do not match
target_->recv(p,h);
return;
}
received_packets++;
if (shape_queue.length() == 0) {
// There are no packets being shapped. Tests profile.
if (in_profile(p)) {
sent_packets++;
target_->recv(p,h);
} else {
if (shape_packet(p))
schedule_packet(p);
// else
// Shaper is being used as a dropper
}
} else {
// There are packets being shapped. Shape this packet too.
shape_packet(p);
}
}
bool DSShaper::shape_packet(Packet *p)
{
if (shape_queue.length() >= max_queue_length) {
drop (p);
dropped_packets++;
return (false);
}
shape_queue.enque(p);
shaped_packets++;
return (true);
}
void DSShaper::schedule_packet(Packet *p)
{
// calculate time to wake up
int packetsize = hdr_cmn::access(p)->size_ * 8 ;
double delay = (packetsize - curr_bucket_contents)/peak_;
Scheduler& s = Scheduler::instance();
s.schedule(&sh_, p, delay);
}
void DSShaper::resume()
{
Packet *p = shape_queue.deque();
if (in_profile(p)) {
sent_packets++;
target_->recv(p,(Handler*) NULL);
} else {
// This is not an expected error, because the packet was scheduled to wake up
// exactly when it could be sent
puts ("shaper/resume - This error should not occur!\n");
drop (p);
dropped_packets++;
}
if (shape_queue.length() > 0) {
// There are packets in the queue. Schedule the first one.
Packet *first_p = shape_queue.lookup(0);
// Got the first packet in the queue.
schedule_packet(first_p);
}
}
bool DSShaper::in_profile(Packet *p)
{
update_bucket_contents() ;
int packetsize = hdr_cmn::access(p)->size_ * 8 ; // in bits
if (packetsize > curr_bucket_contents)
return false;
else {
curr_bucket_contents -= packetsize ;
return true ;
}
}
void DSShaper::update_bucket_contents()
{
// I'm using the token bucket implemented by Sean Murphy
double current_time = Scheduler::instance().clock() ;
double added_bits = (current_time - last_time) * peak_ ;
curr_bucket_contents += (int) (added_bits + 0.5);
if (curr_bucket_contents > burst_size_)
curr_bucket_contents=burst_size_ ;
last_time = current_time ;
}
int DSShaper::command(int argc, const char* const*argv)
{
if (argc==2) {
if (strcmp(argv[1],"reset-counters")==0) {
reset_counters() ;
return TCL_OK ;
}
if (strcmp(argv[1],"get-received-packets")==0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%d",received_packets);
return TCL_OK ;
}
if (strcmp(argv[1],"get-sent-packets")==0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%d",sent_packets);
return TCL_OK ;
}
if (strcmp(argv[1],"get-shaped-packets")==0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%d",shaped_packets);
return TCL_OK ;
}
if (strcmp(argv[1],"get-dropped-packets")==0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%d",dropped_packets);
return TCL_OK ;
}
}
if (argc==3) {
if (strcmp("set-peak-rate", argv[1])==0) {
peak_ = atof(argv[2]);
return TCL_OK ;
}
if (strcmp("set-burst-size", argv[1])==0) {
burst_size_ = curr_bucket_contents = atoi(argv[2]);
return TCL_OK ;
}
if (strcmp("set-fid", argv[1])==0) {
flow_id_ = atoi(argv[2]);
return TCL_OK ;
}
if (strcmp("set-queue-length", argv[1])==0) {
max_queue_length = atoi(argv[2]);
return TCL_OK ;
}
return Connector::command(argc,argv) ;
}
return Connector::command(argc, argv) ;
}
void DSShaper::reset_counters()
{
received_packets = sent_packets = shaped_packets = dropped_packets = 0 ;
}