[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