[Click] nsclick - improving performance: SNS / Fast-NS
Michael Neufeld
neufeldm at cs.colorado.edu
Fri May 7 09:57:50 EDT 2004
I've seen those, and have considered the idea of merging nsclick with
them. I've had other things taking up my time, so haven't had a chance
to look at it in much detail. Offhand I'd say it ought to be possible to
use them, and it shouldn't be too traumatic, though it may require a bit
of manually picking through patch files.
If you're having speed problems right now, I've got a hack which should
help in the short term. Something changed in the scheduler in ns-2 when
moving from 2.1b9 and 2.26 which caused heavy slowdowns when scheduling
a lot of events at the same time. I don't recall what exactly changed,
but the hack I applied mitigated it. I was going to do a real fix for
the next nsclick release, but that's been a little longer coming than I
thought it would be. In any case, I've attached versions of
classifier-click.h and classifier-click.cc with the speedup patch
applied. It's not pretty, but it does seem to help performance.
-Mike
Michael Voorhaen wrote:
> Hi all,
>
> I came across two solutions that claim to speed up NS quite a bit. First of
> all SNS which claims to have complexity O(N) instead of O(N²), with N being
> the number of nodes. (See the text at the bottom for more info). The other
> is Fast-NS which also seems to get good results).
>
> My question to you: Has anyone ever tried these tools to improve performance
> with nsclick, or if not do you think it would be possible to use them.
>
> SNS is based on ns2-1.9 which might cause some problems. I have no idea if
> it is possible to incorporate the changes into ns2-2.26. So far I haven't
> been able to compile SNS yet, so I have little experience with it.
>
> Fast-NS is something one of my colleagues showed me earlier today. Its
> changes have already been incorporated into ns2-2.27, and there is a patch
> available for ns2-2.26. So most likely this would work, since the paper
> doesn't describe any changes that would affect the click functionality.
>
> The speed-ups of both techniques only show up when simulation over 100
> nodes, so in many case the technique will not help much. However for larger
> simulations the speed up seems to be really good.
>
> Any comments are appreciated.
>
> Best regards,
> Michael Voorhaen
>
> PS: the mail on SNS I received from the manet mailinglist last week
>
> Dear Ravi,
>
> Three critical properties for network simulators are accuracy,
> speed, and scale. ns2 and glomosim are pretty much equivalent on all three
> axis. On accuracy, the core simulators, the protocol
> implementations, and the physical propagation and energy consumption models
> have been vetted by the community. On speed & scale, the two simulators are
> equally bad. In scenarios commonly used for evaluating
> ad hoc routing protocols (e.g. [1]), ns2 and glomosim perform and scale with
> O(N^2), where N is number of nodes, with constant factors in the same
> ballpark. In short, you will likely end up wasting a lot of time waiting for
> ns2 or glomosim to finish. The choice between ns2 and glomosim thus comes
> down to convenience of their respective programming environments.
>
> I would like to point out SNS, an alternative simulator whose accuracy is
> identical to ns2, but whose performance and scalability are
> significantly better. SNS is freely available for downloads here:
> http://www.cs.cornell.edu/people/egs/sns/
>
> SNS is based on the same code base as ns2 - it shares the same protocol
> implementations, the same physical propagation model and the same energy
> consumption parameters. We have extensively checked its correctness against
> ns2 (Note that simulations typically have some amount of non-determinism,
> e.g. when packets are sent at precisely the same time, simulators may pick a
> different global order. These effects may cascade and lead to slight
> differences. When we force SNS and ns2 to follow the same global order, they
> compute bit-for-bit identical results).
>
> The main contribution in SNS is a restructuring of the internal events of
> the simulation engine to cache and reuse computations. SNS
> eliminates redundant, expensive computations both within and across
> simulation runs through function caching and reuse. This enables SNS to
> achieve performance and scale proportional to O(N) for common ad hoc
> networking scenarios. SNS runs accurate 10000-node simulations in under an
> hour.
>
> The SNS programming environment is identical to ns2 - protocol
> implementations written for SNS should work in ns2 without any
> modifications, and vice versa.
>
> Choosing a simulator is quite a difficult topic, open to religious arguments
> of the kind one occasionally encounters in the comparison
> of programming languages. I hope this message pointed out three
> objective, scientific metrics for choosing a suitable simulator, and
> suggested an alternative that improves two out of the three with no loss of
> accuracy.
>
> Gun.
>
> --
>
> [1] Josh Broch, David A. Maltz, David B. Johnson, Yih-Chun Hu, and Jorjeta
> Jetcheva. A Performance Comparison of Multi-Hop Wireless Ad Hoc Network
> Routing Protocols. In Proceedings of the Fourth Annual ACM/IEEE
> International Conference on Mobile Computing and Networking, ACM, Dallas,
> TX, October 1998.
>
> [2] Kevin Walsh, Emin Gun Sirer. Staged Simulation: A General Technique for
> Improving Simulation Scale and Performance. To appear in ACM Transactions on
> Modeling and Computer Simulation (TOMACS), April 2004.
>
> [3] Kevin Walsh, Emin Gun Sirer. Staged Simulation for Improving the Scale
> and Performance of Wireless Network Simulations. In Procedings of the Winter
> Simulation Conference, New Orleans, LA, December 2003.
>
> Ravi kumar writes:
>
>>Hi all,
>>
>> I am working on wireless security and i have
>>to implement an algorithm on wireless networks, ad-hoc
>>in particular.
>>
>> I have seen some discussion in this group on
>>both Ns-2 and Glomosim.I'd like to find out which one
>>is better in regard to functionality and ease of use.
>>i know that ns-2 is a generally accepted standard for simulation in
>>the academic community. i dont know much about glomosim, anyway if i
>>need a opinion i guess this is the place to ask.
>>
>> waiting for your views. thanks in advance
>>
>>ravi
>>
>>
>>
>>
>>__________________________________
>>Do you Yahoo!?
>>Win a $20,000 Career Makeover at Yahoo! HotJobs
>>http://hotjobs.sweepstakes.yahoo.com/careermakeover
>>
>>_______________________________________________
>>manet mailing list
>>manet at ietf.org
>>https://www1.ietf.org/mailman/listinfo/manet
>>
>
>
>
> _______________________________________________
> manet mailing list
> manet at ietf.org
> https://www1.ietf.org/mailman/listinfo/manet
>
> ========================================================
> Michael Voorhaen
> ========================================================
> Phd Student
> Dept. of Mathematics and Computer Sciences
> PATS (Performance Analysis of Telecommunication Systems)
> University of Antwerp
> Middelheimlaan 1
> 2020 Antwerpen, Belgium
> G1.11
> Phone: 03/2653905
> Mail: michael.voorhaen at ua.ac.be
> ========================================================
>
>
> _______________________________________________
> click mailing list
> click at amsterdam.lcs.mit.edu
> https://amsterdam.lcs.mit.edu/mailman/listinfo/click
-------------- next part --------------
/*
* classifier-click classifier file for nsclick
* $Header: /srl/dirkcvs/nsclick/ns/classifier/classifier-click.cc,v 1.15 2003/07/12 06:02:08 neufeldm Exp $
*/
/*****************************************************************************
* Copyright 2002, Univerity of Colorado at Boulder. *
* *
* All Rights Reserved *
* *
* Permission to use, copy, modify, and distribute this software and its *
* documentation for any purpose other than its incorporation into a *
* commercial product is hereby granted without fee, provided that the *
* above copyright notice appear in all copies and that both that *
* copyright notice and this permission notice appear in supporting *
* documentation, and that the name of the University not be used in *
* advertising or publicity pertaining to distribution of the software *
* without specific, written prior permission. *
* *
* UNIVERSITY OF COLORADO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS *
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
* FITNESS FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL THE UNIVERSITY *
* OF COLORADO BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL *
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA *
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER *
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR *
* PERFORMANCE OF THIS SOFTWARE. *
* *
****************************************************************************/
#include "config.h"
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#include <unistd.h>
//#include <stl.h>
//#include <hash_map.h>
#include <map>
#include <string>
#include <deque>
#include "agent.h"
#include "packet.h"
#include "rawpacket.h"
#include "ip.h"
#include "extrouter.h"
#include "classifier.h"
#include "classifier-ext.h"
#include "mobilenode.h"
#include "clicknode.h"
#include "address.h"
#include <simclick.h>
#include "scheduler.h"
#include "classifier-click.h"
#include "ll-ext.h"
#include "clickqueue.h"
static class ClickClassifierClass : public TclClass {
public:
ClickClassifierClass() : TclClass("Classifier/Ext/Click") {}
TclObject* create(int, const char*const*) {
return (new ClickClassifier());
}
} class_click_classifier;
void
ClickEventHandler::handle(Event* event) {
// XXX dangerous downcast - should use RTTI
ClickEvent* cevent = (ClickEvent*) event;
simclick_simstate esimstate;
esimstate.curtime = cevent->when_;
//fprintf(stderr,"Should be calling simclick_click_run: %lf\n",event->time_);
while (!cevent->clickinst_.empty()) {
simclick_click_run(cevent->clickinst_.front(),&esimstate);
cevent->clickinst_.pop_front();
}
ClickClassifier::global_clickevents_.erase(cevent->when_);
delete cevent;
}
map<MACAddr,int> ClickClassifier::global_mactonodemap_;
map<MACAddr,int> ClickClassifier::global_mactonsmacmap_;
map<u_int32_t,int> ClickClassifier::global_ipmap_;
map<struct timeval,ClickEvent*> ClickClassifier::global_clickevents_;
ClickClassifier::ClickClassifier() {
extrouter_ = this;
clickinst_ = NULL;
}
int
ClickClassifier::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (2 == argc) {
if (strcmp(argv[1], "getnodename") == 0) {
// getnodename
tcl.resultf(nodename_.c_str());
return TCL_OK;
}
if (strcmp(argv[1], "runclick") == 0) {
// runclick
if (clickinst_) {
simclick_simstate simstate;
simstate.curtime = GetSimTime();
simclick_click_run(clickinst_,&simstate);
}
return TCL_OK;
}
}
else if (3 == argc) {
if(strcmp(argv[1], "loadclick") == 0) {
simclick_simstate simstate;
simstate.curtime = GetSimTime();
clickinst_ = simclick_click_create((simclick_sim)this,argv[2],&simstate);
simclick_click_run(clickinst_,&simstate);
return TCL_OK;
}
if (strcmp(argv[1], "getip") == 0) {
// getip <ifname>
int theif = simclick_sim_ifid_from_name((simclick_sim)this,argv[2]);
//fprintf(stderr,"get ipaddr is %s\n",ifipaddrs_[theif].c_str());
tcl.resultf(ifipaddrs_[theif].c_str());
return TCL_OK;
}
if (strcmp(argv[1], "getmac") == 0) {
// getmac <ifname>
int theif = simclick_sim_ifid_from_name((simclick_sim)this,argv[2]);
//fprintf(stderr,"get macaddr is %s\n",ifmacaddrs_[theif].c_str());
tcl.resultf(ifmacaddrs_[theif].c_str());
return TCL_OK;
}
if (strcmp(argv[1], "setnodename") == 0) {
// setnodename <ifname>
nodename_ = argv[2];
return TCL_OK;
}
if (strcmp(argv[1], "setnodeaddr") == 0) {
// setnodeaddr <nodeaddress>
nodeaddr_ = Address::instance().str2addr(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "setnode") == 0) {
// setnode <node>
node_ = argv[2];
return TCL_OK;
}
}
else if (4 == argc) {
if(strcmp(argv[1], "setip") == 0) {
// setip <ifname> <ipaddr>
int theif = simclick_sim_ifid_from_name((simclick_sim)this,argv[2]);
ifipaddrs_[theif] = string(argv[3]);
//fprintf(stderr,"ipaddr is %s\n",ifipaddrs_[theif].c_str());
// Also save the binary form of this IP address in a static
// (i.e. simulator global) hash map of IP addresses to ns-2
// addresses. This lets us track map IP to ns-2 address when
// we might need it.
global_ipmap_[inet_addr(argv[3])] = nodeaddr_;
return TCL_OK;
}
else if(strcmp(argv[1], "setmac") == 0) {
// setmac <ifname> <macaddr>
int theif = simclick_sim_ifid_from_name((simclick_sim)this,argv[2]);
ifmacaddrs_[theif] = string(argv[3]);
//fprintf(stderr,"macaddr is %s\n",ifmacaddrs_[theif].c_str());
// Also save the binary form of this MAC address in a static
// (i.e. simulator global) hash map of MAC addresses to ns-2
// addresses. This lets us set the destination address in the
// ns-2 packet header.
MACAddr thismacaddr = MACAddr(string(argv[3]));
global_mactonodemap_[thismacaddr] = nodeaddr_;
LL* mylink = (LL*) slot_[theif];
global_mactonsmacmap_[thismacaddr] = mylink->macDA();
return TCL_OK;
}
else if (strcmp(argv[1], "readhandler") == 0) {
char* readreturn = 0;
readreturn = simclick_click_read_handler(clickinst_,argv[2],argv[3],0,0);
//fprintf(stderr, "readhandler: %s\n",clickretc);
if (readreturn) {
tcl.resultf("%s", readreturn);
free(readreturn);
readreturn = 0;
}
else {
tcl.resultf("");
}
return TCL_OK;
}
} else if (argc == 5) {
if (strcmp(argv[1], "writehandler") == 0) {
int clickret;
clickret = simclick_click_write_handler(clickinst_, argv[2], argv[3],
argv[4]);
//fprintf(stderr, "writehandler: %i\n",clickret);
tcl.resultf("%i", clickret);
return TCL_OK;
}
}
return ExtClassifier::command(argc, argv);
}
ClickClassifier::~ClickClassifier() {
}
int
ClickClassifier::route(Packet* p) {
int result = 0;
if (clickinst_) {
unsigned char* data = NULL;
int len = ((PacketData*)(p->userdata()))->size();
simclick_simpacketinfo simpinfo;
hdr_cmn* chdr = HDR_CMN(p);
int ifid = chdr->iface_;
hdr_ip* iphdr = hdr_ip::access(p);
simpinfo.id = chdr->uid();
simpinfo.fid = iphdr->flowid();
hdr_raw* rhdr = hdr_raw::access(p);
int nssubtype = rhdr->subtype;
int clicktype = GetClickPacketType(nssubtype);
simpinfo.simtype = rhdr->ns_type;
unsigned char* pdat = p->accessdata();
data = new unsigned char[len];
memcpy(data,pdat,len);
/*
* XXX Destroy packet for now. This may change if we wind
* up having to track and reuse ns packets after they've gone through
* click.
*/
Packet::free(p);
p = NULL;
simclick_simstate simstate;
simstate.curtime = GetSimTime();
//fprintf(stderr,"Sending packet up to click...\n");
simclick_click_send(clickinst_,&simstate,ifid,clicktype,data,len,&simpinfo);
delete[] data;
data = 0;
}
else {
fprintf(stderr,"No click upcall set!\n");
}
return result;
}
string
ClickClassifier::GetIPAddr(int ifid) {
return ifipaddrs_[ifid];
}
string
ClickClassifier::GetMACAddr(int ifid) {
return ifmacaddrs_[ifid];
}
string
ClickClassifier::GetNodeName() {
return nodename_;
}
string
ClickClassifier::GetNode() {
return node_;
}
/*
* Click service methods
*/
int simclick_sim_ifid_from_name(simclick_sim simid, const char* ifname) {
int ifid = -1;
char* devname = NULL;
/*
* Provide a mapping between a textual interface name
* and the id numbers used. This is mostly for the
* benefit of click scripts, i.e. you can still refer to
* an interface as, say, /dev/eth0.
*/
if (strstr(ifname,"tap") || strstr(ifname,"tun")) {
/*
* A tapX or tunX interface goes to and from the kernel -
* always IFID_KERNELTAP
*/
ifid = ExtRouter::IFID_KERNELTAP;
}
else if ((devname = strstr(ifname,"eth"))) {
/*
* Anything with an "eth" followed by a number is
* a regular interface. Add the number to IFID_FIRSTIF
* to get the handle.
*/
while (*devname && !isdigit(*devname)) {
devname++;
}
if (*devname) {
ifid = atoi(devname) + ExtRouter::IFID_FIRSTIF;
}
}
else if ((devname = strstr(ifname,"drop"))) {
/*
* Anything with an "drop" followed by a number is
* a special interface on which we place packets that
* get dropped due to MAC layer feedback. Add the number to
* IFID_FIRSTIFDROP to get the handle.
*/
while (*devname && !isdigit(*devname)) {
devname++;
}
if (*devname) {
ifid = atoi(devname) + ExtRouter::IFID_FIRSTIFDROP;
}
}
return ifid;
}
int
simclick_sim_send_to_if(simclick_sim siminst,simclick_click clickinst,
int ifid,int type, const unsigned char* data,int len,
simclick_simpacketinfo* pinfo) {
if (NULL == siminst) {
return -1;
}
/*
* Bail out if we get a bad ifid
*/
if (ExtRouter::IFID_LASTIF < ifid) {
return -1;
}
/*
* XXX should probably use RTTI typesafe casts if they are now
* reliably implemented across the compilers/platforms we want
* to run on.
*/
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
return theclassifier->send_to_if(ifid,type,data,len,pinfo);
}
int
simclick_sim_schedule(simclick_sim siminst,simclick_click clickinst,
struct timeval* when) {
int result = 0;
ClickEvent* ev = ClickClassifier::global_clickevents_[*when];
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
if (!ev) {
ev = new ClickEvent();
ev->when_ = *when;
double simtime = when->tv_sec + (when->tv_usec/1.0e6);
double simdelay = simtime - Scheduler::instance().clock();
ClickClassifier::global_clickevents_[*when] = ev;
Scheduler::instance().schedule(&(theclassifier->cevhandler_),ev,simdelay);
}
ev->clickinst_.push_back(clickinst);
//fprintf(stderr,"Event scheduled in %f seconds\n",simdelay);
return result;
}
void
simclick_sim_ipaddr_from_name(simclick_sim siminst,const char* ifname,
char* buf,int len) {
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
int theif = simclick_sim_ifid_from_name(siminst,ifname);
string ipaddr = theclassifier->GetIPAddr(theif);
memset(buf,0,len);
ipaddr.copy(buf,len-1);
}
void
simclick_sim_macaddr_from_name(simclick_sim siminst,const char* ifname,
char* buf,int len) {
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
int theif = simclick_sim_ifid_from_name(siminst,ifname);
string macaddr = theclassifier->GetMACAddr(theif);
memset(buf,0,len);
macaddr.copy(buf,len-1);
}
void
simclick_sim_get_node_name(simclick_sim siminst,char* buf,int len) {
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
string nodename = theclassifier->GetNodeName();
memset(buf,0,len);
nodename.copy(buf,len-1);
}
void
simclick_sim_node_exec(simclick_sim siminst,simclick_click clickinst,
const char* cmd) {
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
string thenode = theclassifier->GetNode();
Tcl& tcl = Tcl::instance();
tcl.evalf("%s %s",thenode.c_str(),cmd);
}
int
ClickClassifier::send_to_if(int ifid,int type,const unsigned char* data,
int len,simclick_simpacketinfo* pinfo) {
int result = 0;
Tcl& tcl = Tcl::instance();
/*
* Package raw data into an ns-2 format raw packet, then send
* it on down the line.
*/
Packet* pkt = MakeRawPacket(type,ifid,data,len,pinfo);
//fprintf(stderr,"simclickid == %d\n",simclickid);
recv(pkt,0);
return result;
}
int
ClickClassifier::IFReady(int ifid) {
NsObject* target = NULL;
int ready = 0;
// XXX assumes direct ifid->slot mapping
if (ExtRouter::IFID_KERNELTAP == ifid) {
return 1;
}
target = slot_[ifid];
if (target) {
LLExt* llext = (LLExt*) target;
ready = llext->ready();
}
else {
ready = 0;
fprintf(stderr,"ERROR: network interface does not exist\n");
}
return ready;
}
int
simclick_sim_if_ready(simclick_sim siminst,simclick_click clickinst,int ifid) {
int result = 0;
ClickClassifier* theclassifier = (ClickClassifier*)siminst;
result = theclassifier->IFReady(ifid);
return result;
}
int
ClickClassifier::GetNSSubtype(int type) {
switch (type) {
case SIMCLICK_PTYPE_ETHER:
return hdr_raw::ETHERNET;
case SIMCLICK_PTYPE_IP:
return hdr_raw::IP;
default:
return hdr_raw::NONE;
}
return hdr_raw::NONE;
}
int
ClickClassifier::GetClickPacketType(int nssubtype) {
switch (nssubtype) {
case hdr_raw::ETHERNET:
return SIMCLICK_PTYPE_ETHER;
case hdr_raw::IP:
return SIMCLICK_PTYPE_IP;
default:
return SIMCLICK_PTYPE_UNKNOWN;
}
return SIMCLICK_PTYPE_UNKNOWN;
}
// XXX
// Normally I'd bitterly complain about code like this. However,
// I don't really want to worry about annoying differences
// between IP header files across different platforms, and I
// want to get this code up and running ASAP. So... I'm defining
// a few things here to handle the minimal packet cracking I
// need to do to create raw packets. If more complicated
// packet munging is called for, something better should be created.
#define NS_ETHER_OFFSET_DADDR 0
#define NS_ETHER_OFFSET_SADDR 6
#define NS_ETHER_HEADER_SIZE 14
void
ClickClassifier::LinkLayerFailedCallback(Packet* p, void* arg) {
// Hit the callback and then free the packet
((ClickClassifier*)arg)->LinkLayerFailed(p);
Packet::free(p);
}
void
ClickClassifier::LinkLayerFailed(Packet* p) {
//fprintf(stderr,"XXX Lost a packet!!!\n");
if (clickinst_) {
unsigned char* data = NULL;
int len = ((PacketData*)(p->userdata()))->size();
simclick_simpacketinfo simpinfo;
hdr_cmn* chdr = HDR_CMN(p);
int ifid = chdr->iface_ + IFID_LASTIF;
hdr_ip* iphdr = hdr_ip::access(p);
simpinfo.id = chdr->uid();
simpinfo.fid = iphdr->flowid();
hdr_raw* rhdr = hdr_raw::access(p);
int nssubtype = rhdr->subtype;
int clicktype = GetClickPacketType(nssubtype);
unsigned char* pdat = p->accessdata();
data = new unsigned char[len];
memcpy(data,pdat,len);
simclick_simstate simstate;
simstate.curtime = GetSimTime();
//fprintf(stderr,"Sending packet up to click...\n");
simclick_click_send(clickinst_,&simstate,ifid,clicktype,data,len,&simpinfo);
delete data;
data = 0;
}
else {
fprintf(stderr,"No click upcall set!\n");
}
}
Packet*
ClickClassifier::MakeRawPacket(int type,int ifid,const unsigned char* data,
int len,simclick_simpacketinfo* pinfo){
Packet* pkt = Packet::alloc(len);
/*
* Shovel raw data into packet
*/
hdr_raw* rhdr = hdr_raw::access(pkt);
rhdr->subtype = GetNSSubtype(type);
unsigned char* pdat = pkt->accessdata();
memcpy(pdat,data,len);
/*
* Set some of the packet header stuff ns-2 wants
*/
struct hdr_cmn* chdr = HDR_CMN(pkt);
chdr->iface() = ifid;
chdr->ptype() = PT_RAW;
chdr->size() = len;
if (pinfo->id >= 0) {
chdr->uid() = pinfo->id;
}
else {
chdr->uid() = Agent::getnextuid();
}
rhdr->ns_type = (-1 == pinfo->simtype) ? PT_RAW : pinfo->simtype;
chdr->xmit_failure_ = LinkLayerFailedCallback;
chdr->xmit_failure_data_ = (void*)this;
hdr_ip* iphdr = hdr_ip::access(pkt);
iphdr->flowid() = 0;
if (pinfo->fid >= 0) {
iphdr->flowid() = pinfo->fid;
}
/*
* A packet coming in from click on the kernel tap device is
* considered to be going up into the node, on any other device
* going down out of it.
*/
if (ExtRouter::IFID_KERNELTAP == ifid) {
chdr->direction() = hdr_cmn::UP;
}
else {
chdr->direction() = hdr_cmn::DOWN;
// Going out to a network adapter, and we're already
// ethernet encapsulated. The ns-2 interface code will
// tack on ethernet header overhead as well, so we subtract
// it out of our simulated size here to avoid actual packet
// size inflation
if (hdr_raw::ETHERNET == rhdr->subtype) {
chdr->size() -= NS_ETHER_HEADER_SIZE;
}
}
// If we've got ethernet encapsulation, translate mac address
// to ns address. Otherwise we're SOL.
struct hdr_mac* mhdr = HDR_MAC(pkt);
if (hdr_raw::ETHERNET == rhdr->subtype) {
MACAddr dmac(data + NS_ETHER_OFFSET_DADDR);
MACAddr smac(data + NS_ETHER_OFFSET_SADDR);
if (dmac.is_broadcast()) {
mhdr->macDA_ = MAC_BROADCAST;
chdr->next_hop_ = -1;
}
else {
mhdr->macDA_ = global_mactonsmacmap_[dmac];
chdr->next_hop_ = global_mactonodemap_[dmac];
//fprintf(stderr,"XXX using real MAC: %s -> %d\n",dmac.to_string().c_str(),mhdr->macDA_);
}
mhdr->macSA_ = global_mactonsmacmap_[smac];
chdr->next_hop_ = global_mactonodemap_[dmac];
chdr->prev_hop_ = global_mactonodemap_[smac];
}
else {
//fprintf(stderr,"XXX using broadcast mac XXX\n");
mhdr->macDA_ = MAC_BROADCAST;
}
// Got an IP packet? Must have come from click, and therefore
// the next hop is us.
if ((ExtRouter::IFID_KERNELTAP == ifid) && (hdr_raw::IP == rhdr->subtype)) {
chdr->next_hop() = nodeaddr_;
}
return pkt;
}
struct timeval
ClickClassifier::GetSimTime() {
struct timeval curtime;
double ns2time = Scheduler::instance().clock();
double fracp,intp;
fracp = modf(ns2time,&intp);
curtime.tv_sec = intp;
curtime.tv_usec = (fracp * 1.0e6 + 0.5);
return curtime;
}
-------------- next part --------------
/*
*
* This might not seem like a regular classifier, and it isn't.
* It essentially has a fixed interface ID which it sends along
* with its packet to the ClickNode it lives on, the idea being
* that the Click subsystem will be the thing which actually
* does the classifying, not the classifier.
*
* $Header: /srl/dirkcvs/nsclick/ns/classifier/classifier-click.h,v 1.8 2003/07/12 06:02:08 neufeldm Exp $
*/
/*****************************************************************************
* Copyright 2002, Univerity of Colorado at Boulder. *
* *
* All Rights Reserved *
* *
* Permission to use, copy, modify, and distribute this software and its *
* documentation for any purpose other than its incorporation into a *
* commercial product is hereby granted without fee, provided that the *
* above copyright notice appear in all copies and that both that *
* copyright notice and this permission notice appear in supporting *
* documentation, and that the name of the University not be used in *
* advertising or publicity pertaining to distribution of the software *
* without specific, written prior permission. *
* *
* UNIVERSITY OF COLORADO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS *
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
* FITNESS FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL THE UNIVERSITY *
* OF COLORADO BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL *
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA *
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER *
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR *
* PERFORMANCE OF THIS SOFTWARE. *
* *
****************************************************************************/
#ifndef ns_classifier_click_h
#define ns_classifier_click_h
#include "object.h"
class Packet;
class ClickEvent : public Event {
public:
// Keep a list of clickinstances around so we can run all
// of them with only one scheduled event.
// XXX may want to turn this into a hash to avoid needlessly running
// the click graph...
deque<simclick_click> clickinst_;
// Store an extra copy of the call time in sec/usec format.
// This is to sidestep some roundoff errors which occured
// when going back and forth between sec/usec and doubles.
struct timeval when_;
};
class ClickEventHandler : public Handler {
public:
virtual void handle(Event* event);
};
class MACAddr {
public:
MACAddr() {
memset(macaddr_,0,6);
}
explicit MACAddr(const string straddr) {
sscanf(straddr.c_str(), "%02X:%02X:%02X:%02X:%02X:%02X", &macaddr_[0],
&macaddr_[1], &macaddr_[2], &macaddr_[3], &macaddr_[4],
&macaddr_[5]);
}
explicit MACAddr(const unsigned char* rawaddr) {
memcpy(macaddr_,rawaddr,6);
}
bool operator==(const MACAddr& rhs) const {
return(0 == memcmp(macaddr_,rhs.macaddr_,6));
}
bool is_broadcast() {
for (int i=0;i<6;i++) {
if (macaddr_[i] != 0xff) {
return false;
}
}
return true;
}
string to_string() {
char tmp[64];
sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X", macaddr_[0],
macaddr_[1], macaddr_[2], macaddr_[3], macaddr_[4],
macaddr_[5]);
return string(tmp);
}
unsigned char macaddr_[6];
};
namespace std {
struct less<MACAddr> {
bool operator()(const MACAddr& l, const MACAddr& r) const {
// Treat MAC as a big old integer...
uint32_t leftu = *((uint32_t*)(l.macaddr_));
uint32_t rightu = *((uint32_t*)(r.macaddr_));
uint16_t leftl = *((uint16_t*)(l.macaddr_+4));
uint16_t rightl = *((uint16_t*)(r.macaddr_+4));
// Check the upper bytes first, if those are equal check lower
if (leftu < rightu) {
return true;
}
else if (leftu == rightu) {
return (leftl < rightl);
}
return false;
}
};
struct less<struct timeval> {
bool operator()(const struct timeval& l, const struct timeval& r) const {
// Simple comparison...
// Check the seconds first, if those are equal check usec
if (l.tv_sec < r.tv_sec) {
return true;
}
else if (l.tv_sec == r.tv_sec) {
return (l.tv_usec < r.tv_usec);
}
return false;
}
};
}
class ClickClassifier : public ExtClassifier,public ExtRouter {
public:
ClickClassifier();
virtual ~ClickClassifier();
virtual int command(int argc, const char*const* argv);
/*
* Stuff to handle click requests
*/
public:
virtual int send_to_if(int ifid,int type,const unsigned char* data,
int len,simclick_simpacketinfo* pinfo);
ClickEventHandler cevhandler_;
// ExtRouter method
virtual int route(Packet* p);
string GetIPAddr(int ifid);
string GetMACAddr(int ifid);
string GetNodeName();
string GetNode();
int IFReady(int ifid);
simclick_click GetClickinst() { return clickinst_; }
static void LinkLayerFailedCallback(Packet* p, void* arg);
void LinkLayerFailed(Packet* p);
static map<struct timeval,ClickEvent*> global_clickevents_;
protected:
int GetNSSubtype(int clicktype);
int GetClickPacketType(int nssubtype);
struct timeval GetSimTime();
Packet* MakeRawPacket(int type,int ifid,const unsigned char* data,int len,
simclick_simpacketinfo* pinfo);
simclick_click clickinst_;
typedef map<int,string> STRmap;
map<int,string> ifipaddrs_;
map<int,string> ifmacaddrs_;
static map<MACAddr,int> global_mactonodemap_;
static map<MACAddr,int> global_mactonsmacmap_;
static map<u_int32_t,int> global_ipmap_;
string nodename_;
string node_;
int nodeaddr_;
};
#endif
More information about the click
mailing list