[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 ;
}