--- ns-allinone-2.32.bak/ns-2.32/mac/mac-bod.cc 1970-01-01 10:00:00.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/mac/mac-bod.cc 2008-04-15 17:43:11.000000000 +1000 @@ -0,0 +1,435 @@ +// Copyright (c) 2006 by the Consiglio Nazionale Ricerche (CNR) area +// della Ricerca di Pisa +// +// All rights reserved. +// +// Permission to use, copy, modify, and distribute this software and its +// documentation in source and binary forms for non-commercial purposes +// and without fee is hereby granted, provided that the above copyright +// notice appear in all copies and that both the copyright notice and +// this permission notice appear in supporting documentation. and that +// any documentation, advertising materials, and other materials related +// to such distribution and use acknowledge that the software was +// developed by the University of Southern California, Information +// Sciences Institute. The name of the University may not be used to +// endorse or promote products derived from this software without +// specific prior written permission. +// +// THE Consiglio Nazionale Ricerche (CNR) makes no representations about +// the suitability of this software for any purpose. THIS SOFTWARE IS +// PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Other copyrights might apply to parts of this software and are so +// noted when applicable. +// +// +// mac-bod.cc +// by Raffaello Secchi (raffaello.secchi@isti.cnr.it), CNR/ISTI + + +#include "delay.h" +#include "connector.h" +#include "packet.h" +#include "random.h" + +#include "arp.h" +#include "ll.h" +#include "mac.h" +#include "mac-tdma.h" +#include "cmu-trace.h" + +/* Initialize Requester and Allocator*/ +TdmaRequester::TdmaRequester(): qMon_(0) +{ + bind("request_",&request_); +} + + +TdmaAllocator::TdmaAllocator() +{ + bind("delay_",&delay_); + bind("active_node_",&active_node_); + bind("max_slot_num_",&max_slot_num_); + schedule_nxt_ = NULL; +} + +AllocatorProportional::AllocatorProportional(): TdmaAllocator() +{ + deficit = 0; + slot_index = 0; +} + + +/* ====================================================================== + TCL Hooks for the simulator + ====================================================================== */ + +static class AllocatorProportionalClass : public TclClass { +public: + AllocatorProportionalClass() : TclClass("Allocator/Proportional") {} + TclObject* create(int, const char*const*) { + return (new AllocatorProportional()); + } +} class_allocator_proportional; + +static class AllocatorTclClass : public TclClass { +public: + AllocatorTclClass() : TclClass("Allocator/Tcl") {} + TclObject* create(int, const char*const*) { + return (new AllocatorTcl()); + } +} class_allocator_tcl; + +static class RequesterConstantClass : public TclClass { +public: + RequesterConstantClass() : TclClass("Requester/Constant") {} + TclObject* create(int, const char*const*) { + return (new RequesterConstant()); + } +} class_requester_constant; + +static class RequesterRBDCClass : public TclClass { +public: + RequesterRBDCClass() : TclClass("Requester/RBDC") {} + TclObject* create(int, const char*const*) { + return (new RequesterRBDC()); + } +} class_requester_rbdc; + +static class RequesterVBDCClass : public TclClass { +public: + RequesterVBDCClass() : TclClass("Requester/VBDC") {} + TclObject* create(int, const char*const*) { + return (new RequesterVBDC()); + } +} class_requester_vbdc; + +static class RequesterTclClass : public TclClass { +public: + RequesterTclClass() : TclClass("Requester/Tcl") {} + TclObject* create(int, const char*const*) { + return (new RequesterTcl()); + } +} class_requester_tcl; + + +/* Reinitialize Allocator and Requester objects after new nodes is created */ +void TdmaAllocator::init() { + + requestv_ = mac_->requestv_; + max_slot_num_ = mac_->max_slot_num_; + tdma_schedule_nxt_ = mac_->tdma_schedule_nxt_; + if (schedule_nxt_) + delete [] schedule_nxt_; + schedule_nxt_ = new int[max_slot_num_]; + active_node_ = mac_->active_node_; + + mac_->allocator_ = this; + +} + +void AllocatorProportional::init(){ + + if (deficit) + delete[] deficit; + + active_node_ = mac_->active_node_; + + deficit = new double[active_node_]; + for(int i=0; i<active_node_; i++) + deficit[i] = 0; + + TdmaAllocator::init(); +} + +void AllocatorTcl::init(){ + + Tcl& tcl = Tcl::instance(); + + active_node_ = mac_->active_node_; + + // initialize AllocatorTcl instvars + tcl.evalf("%s initvar",name()); + + TdmaAllocator::init(); +} + +void TdmaRequester::init() { + requestv_ = mac_->requestv_; + slot_num_ = mac_->slot_num_; + mac_->requester_ = this; +} + +void RequesterTcl::init() { + + Tcl& tcl = Tcl::instance(); + + // initialize RequesterTcl instvars + tcl.evalf("%s initvar",name()); + + TdmaRequester::init(); +} + + +/* ====================================================================== + Command Interface with the interpreter + ====================================================================== */ +int AllocatorProportional::command(int argc, const char*const* argv) +{ + + if (argc == 3) { + if (strcmp(argv[1], "attach") == 0) { + mac_ = (MacTdma*) TclObject::lookup(argv[2]); + if(mac_ == 0) + return TCL_ERROR; + init(); + return TCL_OK; + } + } + return TdmaAllocator::command(argc, argv); +} + +int AllocatorTcl::command(int argc, const char*const* argv) +{ + + if (argc == 3) { + if (strcmp(argv[1], "attach") == 0) { + mac_ = (MacTdma*) TclObject::lookup(argv[2]); + if(mac_ == 0) + return TCL_ERROR; + init(); + return TCL_OK; + } + } + return TdmaAllocator::command(argc, argv); +} + + +int TdmaRequester::command(int argc, const char*const* argv){ + + if (argc == 3) { + if (strcmp(argv[1], "attach") == 0) { + mac_ = (MacTdma*) TclObject::lookup(argv[2]); + if(mac_ == 0) + return TCL_ERROR; + init(); + return TCL_OK; + } + if (strcmp(argv[1], "setifq") == 0) { + ifq_ = (Queue *)TclObject::lookup(argv[2]); + if (!ifq_) + return TCL_ERROR; + return (TCL_OK); + } + if (strcmp(argv[1], "setmon") == 0) { + qMon_ = (QueueMonitor *)TclObject::lookup(argv[2]); + if (!qMon_) + return TCL_ERROR; + return (TCL_OK); + } + } + return TclObject::command(argc,argv); +} + +int RequesterConstant::command(int argc, const char*const* argv) +{ + return TdmaRequester::command(argc, argv); +} + +int RequesterRBDC::command(int argc, const char*const* argv) +{ + return TdmaRequester::command(argc, argv); +} + +int RequesterVBDC::command(int argc, const char*const* argv) +{ + return TdmaRequester::command(argc, argv); +} + +int RequesterTcl::command(int argc, const char*const* argv) +{ + if (argc == 3) { + if (strcmp(argv[1], "attach") == 0) { + mac_ = (MacTdma*) TclObject::lookup(argv[2]); + if(mac_ == 0) + return TCL_ERROR; + init(); + return TCL_OK; + } + } + return TdmaRequester::command(argc, argv); +} + + +/* ====================================================================== + Debugging Routines + ====================================================================== */ + +void TdmaAllocator::printrequests(){ + + for(int i=0; i<active_node_ ; i++ ) + printf("[%d]",requestv_[i]); + printf("\n"); + +} + +void TdmaAllocator::printrequest_nxt(){ + for(int i=0; i<max_slot_num_ ; i++ ) + if (schedule_nxt_[i] == SLOT_UNALLOC) + printf("[N]"); + else + printf("[%d]", schedule_nxt_[i]); + printf("\n"); +} + + +/* Requester Main Functions */ + +void RequesterConstant::dorequest(){ + + /* overwrite previous request */ + requestv_[slot_num_] = request_; +} + +void RequesterRBDC::dorequest(){ + + rate = (qMon_->barrivals() - pin)/(mac_->slot_packet_len_*mac_->num_frame_); + + /* overwrite previous request */ + requestv_[slot_num_] = rate+1; + + pin = qMon_->barrivals(); + tin = NOW; +} + +void RequesterVBDC::dorequest(){ + + buffer = qMon_->barrivals() - qMon_->bdepartures() - qMon_->bdrops(); + /* overwrite previous request */ + printf("%lf %d %d\n",NOW, slot_num_, + buffer/(mac_->slot_packet_len_*mac_->num_frame_)); + requestv_[slot_num_] = buffer/(mac_->slot_packet_len_*mac_->num_frame_)+1; +} + +void RequesterTcl::dorequest(){ + + char wrk[1024]; + Tcl& tcl = Tcl::instance(); + + // call the requester tcl + sprintf(wrk,"%s dorequest",name()); + tcl.evalc(wrk); + + /* overwrite previous request */ + requestv_[slot_num_] = atoi(tcl.result()); + +} + + +/* Main Allocation Functions */ +void TdmaAllocator::allocation(){ + + /* create new timer */ + copy_ = new AllocationDelay(this); + + /* store schedule_nxt to local memory */ + copy_->schedule_ = new int[max_slot_num_]; + + for(int i=0; i<max_slot_num_; i++) + copy_->schedule_[i] = schedule_nxt_[i]; + + /* schedule the allocation */ + copy_->sched(delay_); + + mac_->trace_event("reques",0); + mac_->trace_event("nxt",0); + +} + +void TdmaAllocator::schedule_copy(AllocationDelay* c){ + + /* copy the sent schedule to local MAC */ + for(int i=0; i<max_slot_num_; i++) + tdma_schedule_nxt_[i] = c->schedule_[i]; + + /* free memory */ + delete c; +} + +/* Implements the Proportional */ +void AllocatorProportional::allocation() +{ + int totreq = 0; // sum of all requests + int slot = 0; + int ns = 0; + int si = slot_index; + + // find the sum of all requests + for(int i=0; i<active_node_; i++) + totreq += requestv_[i]; + + // add the previous deficit to current request + if ( totreq > 0 ) + for(int i=0; i<active_node_; i++) + if (i!=slot_index) + deficit[i] += double(max_slot_num_*requestv_[i])/totreq; + + while( slot<max_slot_num_ && ns<active_node_ ) { + + while( ns<active_node_ && deficit[slot_index]<=EPS ) { + slot_index = (slot_index + 1) % active_node_; + ns++; + } + + while( slot<max_slot_num_ && deficit[slot_index]>EPS ) { + deficit[slot_index]--; + schedule_nxt_[slot] = slot_index; + slot++; + } + } + + deficit[si] += double(max_slot_num_*requestv_[si])/totreq; + + // the rest is not allocated + if (slot<max_slot_num_) + for(int i=slot; i<max_slot_num_; i++) + if (deficit[si]>EPS) { + deficit[si]--; + schedule_nxt_[i] = si; + } else + schedule_nxt_[i] = SLOT_UNALLOC; + + /* operation common to all Allocators */ + TdmaAllocator::allocation(); +} + + + +/* Implements the Tcl Embedded allocation function */ +void AllocatorTcl::allocation() +{ + Tcl & tcl = Tcl::instance(); + + char wrk[1024]; + + // initialize the array + for(int i=0; i<active_node_; i++) + tcl.evalf("%s set requestv_(%d) %d",name(),i,requestv_[i]); + + // call Tcl scheduling function + tcl.evalf("%s allocation", name()); + + for(int i=0; i<max_slot_num_; i++){ + sprintf(wrk,"%s set schedule_(%d)",name(),i); + tcl.evalc(wrk); + schedule_nxt_[i] = atoi(tcl.result()); + } + + // operation common to all Allocators + TdmaAllocator::allocation(); +} + + + --- ns-allinone-2.32.bak/ns-2.32/mac/mac-tdma.h 2008-04-15 17:39:53.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/mac/mac-tdma.h 2008-04-15 17:43:11.000000000 +1000 @@ -1,4 +1,3 @@ - /* * mac-tdma.h * Copyright (C) 1999 by the University of Southern California @@ -59,6 +58,8 @@ //#include <debug.h> #include "marshall.h" +#include "queue-monitor.h" + #include <delay.h> #include <connector.h> #include <packet.h> @@ -84,6 +85,8 @@ #define DSSS_PreambleLength 144 // 144 bits #define DSSS_PLCPHeaderLength 48 // 48 bits +#define EPS 0.0000001 + class PHY_MIB { public: u_int32_t CWMin; @@ -129,6 +132,11 @@ /* Quoted from MAC-802.11. */ #define DATA_DURATION 5 +// Indicate that the slot is not allocated +#define SLOT_UNALLOC -2 +#define SLOT_NOREQ 0 + + /* We are using same header structure as 802.11 currently */ struct frame_control { u_char fc_subtype : 4; @@ -174,9 +182,171 @@ u_int32_t seqno; }; -/* Timers */ + class MacTdma; + +/* Make a request to allocator for each Tdma node */ +class TdmaRequester: public TclObject { + +public: + TdmaRequester(); + virtual void dorequest() {}; + + int command(int argc, const char*const* argv); + + // initialize dynamic variables + void init(); + + /* pointer to Queue */ + Queue* ifq_; + QueueMonitor* qMon_; + + +protected: + MacTdma* mac_; + int slot_num_; + int *requestv_; + + /* the request to submit */ + int request_; + +}; + + +class RequesterConstant: public TdmaRequester { + +public: + RequesterConstant(): TdmaRequester() { }; + int command(int argc, const char*const* argv); + + virtual void dorequest(); + +}; + +class RequesterRBDC: public TdmaRequester { + +public: + RequesterRBDC(): TdmaRequester() { }; + int command(int argc, const char*const* argv); + + virtual void dorequest(); + +private: + int rate; + int pin; + double tin; +}; + +class RequesterVBDC: public TdmaRequester { + +public: + RequesterVBDC(): TdmaRequester() { }; + int command(int argc, const char*const* argv); + + virtual void dorequest(); + +private: + int buffer; +}; + +class RequesterTcl: public TdmaRequester { + +public: + RequesterTcl(): TdmaRequester() { }; + int command(int argc, const char*const* argv); + + virtual void dorequest(); + + void init(); +}; + +class AllocationDelay; + +/* Allocator classes */ +class TdmaAllocator: public TclObject { +friend class AllocationDelay; + +public: + TdmaAllocator(); + int command(int argc, const char*const* argv){ + return TclObject::command(argc,argv); + }; + + void virtual allocation(); + int active_node_; + int max_slot_num_; + + void virtual init(); + int *schedule_nxt_; + +protected: + MacTdma* mac_; + + /* request vector */ + int *requestv_; + int *tdma_schedule_nxt_; + void printrequests(); + void printrequest_nxt(); + + /* allocation delay */ + double delay_; + double jitter_; + + AllocationDelay* copy_; + void schedule_copy(AllocationDelay *); + +}; + +/* implements the timer that copy next allocation */ +class AllocationDelay: public TimerHandler { +public: + AllocationDelay(TdmaAllocator* a): TimerHandler() { + allocator_ = a; + } + int * schedule_; + + virtual void expire(Event *e){ + allocator_->schedule_copy(this); + } + + ~AllocationDelay() { + delete [] schedule_; + } + +protected: + TdmaAllocator* allocator_; +}; + +class AllocatorProportional: public TdmaAllocator { + +public: + AllocatorProportional(); + int command(int argc, const char*const* argv); + virtual void allocation(); + void virtual init(); + +protected: + double* deficit; // deficit for allocator + int slot_index; + double creq; +}; + +class AllocatorTcl: public TdmaAllocator { + +public: + AllocatorTcl(): TdmaAllocator() {} ; + int command(int argc, const char*const* argv); + virtual void allocation(); + void virtual init(); +protected: + int slot_index; + +}; + + +/* Timers */ + class MacTdmaTimer : public Handler { public: MacTdmaTimer(MacTdma* m, double s = 0) : mac(m) { @@ -235,7 +405,8 @@ friend class SlotTdmaTimer; friend class TxPktTdmaTimer; friend class RxPktTdmaTimer; - + friend class TdmaAllocator; + public: MacTdma(PHY_MIB* p); void recv(Packet *p, Handler *h); @@ -248,17 +419,47 @@ void recvHandler(Event *e); void sendHandler(Event *e); - protected: - PHY_MIB *phymib_; + static int *requestv_; // The vector of requests done by stations - // Both the slot length and max slot num (max node num) can be configged. + /* Requester and Allocator objects for slot scheduling */ + static TdmaAllocator* allocator_; + TdmaRequester* requester_; + + /* Data structure for tdma scheduling. */ + static int active_node_; // How many nodes needs to be descheduled + + static int *tdma_schedule_nxt_; // The next frame to allocate + + /* TDMA scheduling state. + Currently, we only use a centralized simplified way to do + scheduling. Will work on the algorithm later.*/ + // The max num of slot within one frame. + static int max_slot_num_; + int slot_num_; // The slot number it's allocated. + + /* MAC Trace support */ + EventTrace* et_; + virtual void trace_event(char* event,int val); + + + // Both the slot length and max slot num (max node num) can be configged. int slot_packet_len_; - int max_node_num_; + + // The number of frame after which a request is done + static int num_frame_; + + protected: + PHY_MIB *phymib_; + private: int command(int argc, const char*const* argv); + // dump only allocation + int dump_alloc_; + // Do slot scheduling for the active nodes within one cluster. + void re_allocate(); void re_schedule(); void makePreamble(); void radioSwitch(int i); @@ -282,14 +483,9 @@ logtarget_->recv(p, (Handler*) 0); } - inline double TX_Time(Packet *p) { - double t = DATA_Time((HDR_CMN(p))->size()); - - // printf("<%d>, packet size: %d, tx-time: %f\n", index_, (HDR_CMN(p))->size(), t); - if(t < 0.0) { - drop(p, "XXX"); - exit(1); - } + inline double TX_Time() { + double t = DATA_Time(residue_); + return t; } @@ -303,7 +499,8 @@ TxPktTdmaTimer mhTxPkt_; RxPktTdmaTimer mhRxPkt_; - /* Internal MAC state */ + + /* Internal MAC state */ MacState rx_state_; // incoming state (MAC_RECV or MAC_IDLE) MacState tx_state_; // outgoing state @@ -314,42 +511,36 @@ NsObject* logtarget_; - /* TDMA scheduling state. - Currently, we only use a centralized simplified way to do - scheduling. Will work on the algorithm later.*/ - // The max num of slot within one frame. - static int max_slot_num_; - + int frame_; + // The time duration for each slot. static double slot_time_; /* The start time for whole TDMA scheduling. */ static double start_time_; - - /* Data structure for tdma scheduling. */ - static int active_node_; // How many nodes needs to be scheduled + /* initial slot time */ + double slot_start_time_; + static int *tdma_schedule_; - int slot_num_; // The slot number it's allocated. static int *tdma_preamble_; // The preamble data structure. - + // When slot_count_ = active_nodes_, a new preamble is needed. int slot_count_; + + // The remaining part of packet to send + int residue_; + + // number of request received during active frame + static int num_requests_; // How many packets has been sent out? static int tdma_ps_; static int tdma_pr_; -}; - -double MacTdma::slot_time_ = 0; -double MacTdma::start_time_ = 0; -int MacTdma::active_node_ = 0; -int MacTdma::max_slot_num_ = 0; -int *MacTdma::tdma_schedule_ = NULL; -int *MacTdma::tdma_preamble_ = NULL; + + void watch_alloc(); -int MacTdma::tdma_ps_ = 0; -int MacTdma::tdma_pr_ = 0; +}; #endif /* __mac_tdma_h__ */ --- ns-allinone-2.32.bak/ns-2.32/mac/mac-tdma.cc 2008-04-15 17:39:53.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/mac/mac-tdma.cc 2008-04-15 17:43:11.000000000 +1000 @@ -83,6 +83,21 @@ tx_state_ = (x); \ } +double MacTdma::slot_time_ = 0; +double MacTdma::start_time_ = 0; +int MacTdma::active_node_ = 0; +int MacTdma::max_slot_num_ = 0; +int MacTdma::num_requests_ = 0; +int *MacTdma::tdma_schedule_ = NULL; +int *MacTdma::tdma_preamble_ = NULL; +int *MacTdma::tdma_schedule_nxt_ = NULL; +int *MacTdma::requestv_ = NULL; +TdmaAllocator *MacTdma::allocator_ = NULL; +int MacTdma::num_frame_ = 1; + +int MacTdma::tdma_ps_ = 0; +int MacTdma::tdma_pr_ = 0; + /* Phy specs from 802.11 */ static PHY_MIB PMIB = { DSSS_CWMin, DSSS_CWMax, DSSS_SlotTime, DSSS_CCATime, @@ -90,6 +105,7 @@ DSSS_PLCPHeaderLength }; + /* Timers */ void MacTdmaTimer::start(Packet *p, double time) { @@ -101,12 +117,15 @@ stime = s.clock(); rtime = time; assert(rtime >= 0.0); - + + s.schedule(this, p, rtime); + } void MacTdmaTimer::stop(Packet *p) { + Scheduler &s = Scheduler::instance(); assert(busy_); @@ -155,9 +174,6 @@ mac->sendHandler(e); } -/* ====================================================================== - TCL Hooks for the simulator - ====================================================================== */ static class MacTdmaClass : public TclClass { public: MacTdmaClass() : TclClass("Mac/Tdma") {} @@ -171,43 +187,55 @@ // Frame format: // Pamble Slot1 Slot2 Slot3... MacTdma::MacTdma(PHY_MIB* p) : - Mac(), mhSlot_(this), mhTxPkt_(this), mhRxPkt_(this){ + Mac(), requester_(0), et_(0), dump_alloc_(0), + mhSlot_(this), mhTxPkt_(this), mhRxPkt_(this) { + /* Global variables setting. */ // Setup the phy specs. + static int slot_pointer = 0; + phymib_ = p; - - /* Get the parameters of the link (which in bound in mac.cc, 2M by default), - the packet length within one TDMA slot (1500 byte by default), - and the max number of nodes (64) in the simulations.*/ + + // bind parameters of MacTdma object bind("slot_packet_len_", &slot_packet_len_); - bind("max_node_num_", &max_node_num_); + bind("max_slot_num_", &max_slot_num_); + bind("num_frame_", &num_frame_); + bind("dump_alloc_", &dump_alloc_); + - // slot_packet_len_ = 1500; - // max_node_num_ = 64; // Calculate the slot time based on the MAX allowed data length. slot_time_ = DATA_Time(slot_packet_len_); - /* Calsulate the max slot num within on frame from max node num. - In the simple case now, they are just equal. - */ - max_slot_num_ = max_node_num_; - /* Much simplified centralized scheduling algorithm for single hop - topology, like WLAN etc. + + // Initialize the tdma schedule data structures. + if ( !tdma_schedule_ ) { + tdma_schedule_ = new int[max_slot_num_]; + tdma_preamble_ = new int[max_slot_num_]; + tdma_schedule_nxt_ = new int[max_slot_num_]; + requestv_ = new int[max_slot_num_]; + + for(int i=active_node_; i<max_slot_num_; i++) { + tdma_preamble_[i] = NOTHING_TO_SEND; + tdma_schedule_[i] = SLOT_UNALLOC; + tdma_schedule_nxt_[i] = SLOT_UNALLOC; + requestv_[i] = SLOT_NOREQ; + } + } + + /* + if ( active_node_ < max_slot_num_) { + tdma_preamble_[active_node_] = active_node_; + tdma_schedule_[active_node_] = active_node_; + tdma_schedule_nxt_[active_node_] = active_node_; + } */ - // Initualize the tdma schedule and preamble data structure. - tdma_schedule_ = new int[max_slot_num_]; - tdma_preamble_ = new int[max_slot_num_]; - /* Do each node's initialization. */ // Record the initial active node number. active_node_++; - - if (active_node_ > max_node_num_) { - printf("Too many nodes taking part in the simulations, aborting...\n"); - exit(-1); - } - + + /* Do each node's initialization. */ + // Initial channel / transceiver states. tx_state_ = rx_state_ = MAC_IDLE; tx_active_ = 0; @@ -215,16 +243,28 @@ // Initialy, the radio is off. NOTE: can't use radioSwitch(OFF) here. radio_active_ = 0; - // Do slot scheduling. - re_schedule(); + // Record the start time of the new schedule. + start_time_ = NOW; + + /* Seperate slot_num_ and the node id: + we may have flexibility as node number changes. + */ + slot_num_ = slot_pointer++; + + frame_ = 0; + if ( allocator_ ) + allocator_->init(); + /* Deal with preamble. */ // Can't send anything in the first frame. slot_count_ = FIRST_ROUND; - tdma_preamble_[slot_num_] = NOTHING_TO_SEND; + + residue_ = 0; + + //Start the Slot timer... + mhSlot_.start((Packet *) (& intr_), 0); - //Start the Slot timer.. - mhSlot_.start((Packet *) (& intr_), 0); } /* similar to 802.11, no cached node lookup. */ @@ -237,13 +277,19 @@ return TCL_ERROR; return TCL_OK; } + if (strcmp(argv[1], "eventtrace") == 0) { + et_ = (EventTrace *)TclObject::lookup(argv[2]); + if (!et_) + return TCL_ERROR; + return (TCL_OK); + } } return Mac::command(argc, argv); } /* ====================================================================== - Debugging Routines + Debugging & Tracing Routines ====================================================================== */ void MacTdma::trace_pkt(Packet *p) { @@ -268,12 +314,118 @@ (long) pktTx_, (long) pktRx_, (long) callback_); } +void MacTdma::watch_alloc(){ + + for(int i=0; i<max_slot_num_; i++) + if (tdma_schedule_[i] == SLOT_UNALLOC) + printf("[N]"); + else + printf("[%d]",tdma_schedule_[i]); + printf("\n"); + +} + + +void MacTdma::trace_event(char *event, int val) +{ + + if (et_ == NULL) return; + char *wrk = et_->buffer(); + + if (dump_alloc_) + if ( strcmp(event,"req") != 0 && + strcmp(event,"nxt") != 0 && + strcmp(event,"cur") != 0 ) + return; + + if (wrk != 0) { + if (strcmp(event,"cur") == 0) { + static int *xc = new int[active_node_]; + for(int i=0; i<active_node_; i++) + xc[i] = 0; + sprintf(wrk, "<%d> %lf %sslt ", index_, NOW, event); + for(int i=0; i<max_slot_num_; i++) + if (tdma_schedule_[i] == SLOT_UNALLOC) + sprintf(wrk+strlen(wrk), "[N]"); + else{ + sprintf(wrk+strlen(wrk), "[%d]", tdma_schedule_[i]); + xc[tdma_schedule_[i]]++; + } + sprintf(wrk+strlen(wrk), "\n<%d> %lf %sall ", index_, NOW, event); + for(int i=0; i<active_node_; i++) + sprintf(wrk+strlen(wrk), "%d ", xc[i]); + } else if (strcmp(event,"reques") == 0) { + sprintf(wrk, "<%d> %lf %s ", index_, NOW, event); + for(int i=0; i<active_node_; i++ ) + sprintf(wrk+strlen(wrk),"%d ",requestv_[i]); + } else if (strcmp(event,"nxt") == 0) { + static int *xs = new int[active_node_]; + for(int i=0; i<active_node_; i++) + xs[i] = 0; + sprintf(wrk, "<%d> %lf %sslt ", index_, NOW, event); + for(int i=0; i<max_slot_num_; i++ ) + if (allocator_->schedule_nxt_[i] == SLOT_UNALLOC) + sprintf(wrk+strlen(wrk), "[N]"); + else{ + sprintf(wrk+strlen(wrk), "[%d]", allocator_->schedule_nxt_[i]); + xs[allocator_->schedule_nxt_[i]]++; + } + sprintf(wrk+strlen(wrk), "\n<%d> %lf %sall ", index_, NOW, event); + for(int i=0; i<active_node_; i++) + sprintf(wrk+strlen(wrk), "%d ", xs[i]); + } else if (strcmp(event,"req") == 0) { + static double *prev = new double[active_node_]; + static int *prevb = new int [active_node_]; + static int flg = 0; + // + + if (!flg) { + for(int i=0; i<active_node_; i++){ + prev[i] = 0.0; + prevb[i] = 0; + } + flg = 1; + } + + int queue; + + double dt = 0; + double db = 0; + + dt = NOW - prev[index_]; + + + db = 8*((int)requester_->qMon_->barrivals() - + (int)requester_->qMon_->bdrops()-prevb[index_]); + + prevb[index_] = (int)requester_->qMon_->barrivals() - + (int)requester_->qMon_->bdrops(); + + queue = (int)requester_->qMon_->barrivals() - + (int)requester_->qMon_->bdepartures() - + (int)requester_->qMon_->bdrops(); + + + sprintf(wrk, "<%d> %lf reqpar %d %lf", index_, NOW, + queue,db/dt); + + prev[index_] = NOW; + + } else + sprintf(wrk, "<%d> %lf %s %d", index_, NOW, event, val); + } + + et_->trace(); +} + /* ====================================================================== Packet Headers Routines ====================================================================== */ + int MacTdma::hdr_dst(char* hdr, int dst ) { + struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr; if(dst > -2) STORE4BYTE(&dst, (dh->dh_da)); @@ -282,6 +434,7 @@ int MacTdma::hdr_src(char* hdr, int src ) { + struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr; if(src > -2) STORE4BYTE(&src, (dh->dh_sa)); @@ -306,85 +459,103 @@ return 1; } -/* Do the slot re-scheduling: - The idea of postphone the slot scheduling for one slot time may be useful. -*/ +/* Do slot re-scheduling */ void MacTdma::re_schedule() { - static int slot_pointer = 0; - // Record the start time of the new schedule. - start_time_ = NOW; - /* Seperate slot_num_ and the node id: - we may have flexibility as node number changes. - */ - slot_num_ = slot_pointer++; - tdma_schedule_[slot_num_] = (char) index_; + + /* make the requests */ + if (frame_ == 0 && requester_) { + trace_event("req",slot_num_); + requester_->dorequest(); + } + + frame_ = (frame_ + 1) % num_frame_; + + /* apply next schedule */ + for(int i=0; i<max_slot_num_; i++) + tdma_schedule_[i] = tdma_schedule_nxt_[i]; +} + +/* Do slot re-allocation */ +void MacTdma::re_allocate() { + + num_requests_++; + + // printf("%lf %d %d\n", NOW, num_requests_, slot_num_); + + if (num_requests_ < active_node_) + return; + + if (allocator_) + allocator_->allocation(); + + trace_event("cur",0); + + num_requests_ = 0; } /* To handle incoming packet. */ void MacTdma::recv(Packet* p, Handler* h) { struct hdr_cmn *ch = HDR_CMN(p); + u_int32_t dst; + struct hdr_mac_tdma* dh; + /* Incoming packets from phy layer, send UP to ll layer. Now, it is in receiving mode. */ if (ch->direction() == hdr_cmn::UP) { + + dh = HDR_MAC_TDMA(p); + dst = ETHER_ADDR(dh->dh_da); + // Since we can't really turn the radio off at lower level, - // we just discard the packet. - if (!radio_active_) { - free(p); - //printf("<%d>, %f, I am sleeping...\n", index_, NOW); + // we just discard the packet when is not directed to us + // or is broadcast + if (dst != (u_int32_t) index_ && dst != MAC_BROADCAST) { + Packet::free(p); return; } sendUp(p); - //printf("<%d> packet recved: %d\n", index_, tdma_pr_++); return; + } - + /* Packets coming down from ll layer (from ifq actually), send them to phy layer. Now, it is in transmitting mode. */ - callback_ = h; + + callback_ = h; state(MAC_SEND); sendDown(p); - //printf("<%d> packet sent down: %d\n", index_, tdma_ps_++); + } void MacTdma::sendUp(Packet* p) { - struct hdr_cmn *ch = HDR_CMN(p); - - /* Can't receive while transmitting. Should not happen...?*/ - if (tx_state_ && ch->error() == 0) { - printf("<%d>, can't receive while transmitting!\n", index_); - ch->error() = 1; - }; /* Detect if there is any collision happened. should not happen...?*/ if (rx_state_ == MAC_IDLE) { SET_RX_STATE(MAC_RECV); // Change the state to recv. pktRx_ = p; // Save the packet for timer reference. - /* Schedule the reception of this packet, - since we just see the packet header. */ - double rtime = TX_Time(p); - assert(rtime >= 0); - /* Start the timer for receiving, will end when receiving finishes. */ - mhRxPkt_.start(p, rtime); + mhRxPkt_.start(p, 0); } else { /* Note: we don't take the channel status into account, as collision should not happen... */ printf("<%d>, receiving, but the channel is not idle....???\n", index_); } + } /* Actually receive data packet when RxPktTimer times out. */ void MacTdma::recvDATA(Packet *p){ + /*Adjust the MAC packet size: strip off the mac header.*/ struct hdr_cmn *ch = HDR_CMN(p); - ch->size() -= ETHER_HDR_LEN; + // ch->size() -= ETHER_HDR_LEN; ch->num_forwards() += 1; /* Pass the packet up to the link-layer.*/ @@ -395,17 +566,20 @@ Need to calculate a certain time slot for transmission. */ void MacTdma::sendDown(Packet* p) { u_int32_t dst, src, size; - + + int send_byte; + struct hdr_cmn* ch = HDR_CMN(p); struct hdr_mac_tdma* dh = HDR_MAC_TDMA(p); /* Update the MAC header, same as 802.11 */ - ch->size() += ETHER_HDR_LEN; + // ch->size() += ETHER_HDR_LEN; + dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion; dh->dh_fc.fc_type = MAC_Type_Data; dh->dh_fc.fc_subtype = MAC_Subtype_Data; - + dh->dh_fc.fc_to_ds = 0; dh->dh_fc.fc_from_ds = 0; dh->dh_fc.fc_more_frag = 0; @@ -424,8 +598,30 @@ src = ETHER_ADDR(dh->dh_sa); size = ch->size(); + + if (pktTx_ != NULL) + printf("<%d> warning: buffer is NOT empty\n",index_); + + /* buffer the packet to be sent. */ pktTx_ = p; + + /* initialize the residue to whole packet length */ + residue_ = (HDR_CMN(pktTx_))->size(); + // printf("residue = %d\n",residue_); + + if (slot_count_ >= 0 && tdma_schedule_[slot_count_] == slot_num_ && is_idle()){ + send_byte = slot_packet_len_-int((NOW - slot_start_time_)*bandwidth_/8.0); + if (residue_ <= send_byte) { + /* the packet can be sent immediately since is my turn, + * the MAC is idle and enough space is in slot*/ + tdma_preamble_[slot_count_] = (char) dst; + send(); + residue_ = 0; + return; + } + residue_ -= send_byte; + } } /* Actually send the packet. */ @@ -457,7 +653,7 @@ dst = ETHER_ADDR(dh->dh_da); src = ETHER_ADDR(dh->dh_sa); size = ch->size(); - stime = TX_Time(pktTx_); + stime = TX_Time(); ch->txtime() = stime; /* Turn on the radio and transmit! */ @@ -466,6 +662,7 @@ /* Start a timer that expires when the packet transmission is complete. */ mhTxPkt_.start(pktTx_->copy(), stime); + downtarget_->recv(pktTx_, this); pktTx_ = 0; @@ -509,10 +706,10 @@ dh = HDR_MAC_TDMA(pktTx_); dst = ETHER_ADDR(dh->dh_da); //printf("<%d>, %f, write %d to slot %d in preamble\n", index_, NOW, dst, slot_num_); - tdma_preamble_[slot_num_] = dst; + tdma_preamble_[slot_count_] = dst; } else { //printf("<%d>, %f, write NO_PKT to slot %d in preamble\n", index_, NOW, slot_num_); - tdma_preamble_[slot_num_] = NOTHING_TO_SEND; + tdma_preamble_[slot_count_] = NOTHING_TO_SEND; } } @@ -527,49 +724,64 @@ // Restart timer for next slot. mhSlot_.start((Packet *)e, slot_time_); - // Make a new presamble for next frame. - if ((slot_count_ == active_node_) || (slot_count_ == FIRST_ROUND)) { - //printf("<%d>, %f, make the new preamble now.\n", index_, NOW); + slot_count_++; + + // Make the new preamble for next frame. + if ((slot_count_ == max_slot_num_) || (slot_count_ == FIRST_ROUND)) { + + /* call the requester at the beginning of frame */ + re_schedule(); + + /* call the allocator at the beginning of frame */ + re_allocate(); + // We should turn the radio on for the whole slot time. radioSwitch(ON); - makePreamble(); - slot_count_ = 0; + slot_count_ = -1; return; } // If it is the sending slot for me. - if (slot_count_ == slot_num_) { - //printf("<%d>, %f, time to send.\n", index_, NOW); - // We have to check the preamble first to avoid the packets coming in the middle. - if (tdma_preamble_[slot_num_] != NOTHING_TO_SEND) - send(); - else - radioSwitch(OFF); + if (tdma_schedule_[slot_count_] == slot_num_) { + + slot_start_time_ = NOW; + + if (residue_ <= slot_packet_len_) { + + /* the packet can be sent immediately since is my turn, + * the MAC is idle and enough space is in slot*/ + makePreamble(); + + if (tdma_preamble_[slot_count_] != NOTHING_TO_SEND) + send(); + else + radioSwitch(OFF); - slot_count_++; + residue_ = 0; + return; + } + residue_ -= slot_packet_len_; return; } - + // If I am supposed to listen in this slot - if ((tdma_preamble_[slot_count_] == index_) || ((u_int32_t)tdma_preamble_[slot_count_] == MAC_BROADCAST)) { - //printf("<%d>, %f, preamble[%d]=%d, I am supposed to receive now.\n", index_, NOW, slot_count_, tdma_preamble_[slot_count_]); - slot_count_++; + if ((tdma_preamble_[slot_count_] == index_) || + ((u_int32_t)tdma_preamble_[slot_count_] == MAC_BROADCAST)) { // Wake up the receive packets. radioSwitch(ON); return; } - + // If I dont send / recv, do nothing. - //printf("<%d>, %f, preamble[%d]=%d, nothing to do now.\n", index_, NOW, slot_count_, tdma_preamble_[slot_count_]); radioSwitch(OFF); - slot_count_++; return; } void MacTdma::recvHandler(Event *e) { + u_int32_t dst, src; int size; struct hdr_cmn *ch = HDR_CMN(pktRx_); @@ -605,20 +817,22 @@ /* After transmission a certain packet. Turn off the radio. */ void MacTdma::sendHandler(Event *e) { - // printf("<%d>, %f, send a packet finished.\n", index_, NOW); - + /* Once transmission is complete, drop the packet. p is just for schedule a event. */ - SET_TX_STATE(MAC_IDLE); Packet::free((Packet *)e); - - // Turn off the radio after sending the whole packet - radioSwitch(OFF); - + /* unlock IFQ. */ + SET_TX_STATE(MAC_IDLE); + if(callback_) { Handler *h = callback_; callback_ = 0; h->handle((Event*) 0); - } + } + + /* Turn off the radio after sending the whole packet */ + radioSwitch(OFF); } + + --- ns-allinone-2.32.bak/ns-2.32/Makefile.in 2008-04-15 17:40:01.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/Makefile.in 2008-04-15 17:43:11.000000000 +1000 @@ -232,7 +232,7 @@ common/Decapsulator.o common/Encapsulator.o \ common/encap.o \ mac/channel.o mac/mac.o mac/ll.o mac/mac-802_11.o \ - mac/mac-802_3.o mac/mac-tdma.o mac/smac.o \ + mac/mac-802_3.o mac/mac-tdma.o mac/smac.o mac/mac-bod.o \ mobile/mip.o mobile/mip-reg.o mobile/gridkeeper.o \ mobile/propagation.o mobile/tworayground.o \ mobile/antenna.o mobile/omni-antenna.o \ --- ns-allinone-2.32.bak/ns-2.32/tcl/lib/ns-default.tcl 2008-04-15 17:40:05.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/tcl/lib/ns-default.tcl 2008-04-15 17:43:11.000000000 +1000 @@ -654,7 +654,9 @@ God set debug_ false Mac/Tdma set slot_packet_len_ 1500 -Mac/Tdma set max_node_num_ 64 +Mac/Tdma set num_frame_ 1 +Mac/Tdma set max_slot_num_ 64 +Mac/Tdma set dump_alloc_ 0 LL set mindelay_ 50us LL set delay_ 25us --- ns-allinone-2.32.bak/ns-2.32/tcl/lib/ns-sat.tcl 2008-04-15 17:40:05.000000000 +1000 +++ ns-allinone-2.32/ns-2.32/tcl/lib/ns-sat.tcl 2008-04-15 17:43:11.000000000 +1000 @@ -689,22 +689,21 @@ set toNode_ -1 set enqT_($index_) [$ns create-trace Sat/Enque $f $fromNode_ $toNode_] - $enqT_($index_) target $ifq_($index_) + $enqT_($index_) target [$ll_($index_) down-target] $ll_($index_) down-target $enqT_($index_) set deqT_($index_) [$ns create-trace Sat/Deque $f $fromNode_ $toNode_] - $deqT_($index_) target $mac_($index_) + $deqT_($index_) target [$ifq_($index_) target] $ifq_($index_) target $deqT_($index_) set drpT_($index_) [$ns create-trace Sat/Drop $f $fromNode_ $toNode_] $drpT_($index_) target [$drophead_($index_) target] $drophead_($index_) target $drpT_($index_) - $ifq_($index_) drop-target $drpT_($index_) } # Trace element between mac and ll tracing packets between node and node Node/SatNode instproc trace-inlink-queue {f {index_ 0} } { - $self instvar id_ rcvT_ mac_ ll_ phy_rx_ em_ errT_ + $self instvar id_ rcvT_ mac_ ll_ phy_rx_ em_ errT_ set ns [Simulator instance] set toNode_ $id_ @@ -725,9 +724,92 @@ $rcvT_($index_) target [$mac_($index_) up-target] $mac_($index_) up-target $rcvT_($index_) } - } +Node/SatNode instproc insert-monitor { {index_ 0}} { + $self instvar qMonitor_ snoopIn_ snoopOut_ snoopDrop_ + $self instvar ll_ ifq_ drophead_ bytesInt_ pktsInt_ requester_ + + set snoopIn_($index_) [new SnoopQueue/In] + set snoopOut_($index_) [new SnoopQueue/Out] + set snoopDrop_($index_) [new SnoopQueue/Drop] + + $snoopIn_($index_) target [$ll_($index_) down-target] + $ll_($index_) down-target $snoopIn_($index_) + + $snoopOut_($index_) target [$ifq_($index_) target] + $ifq_($index_) target $snoopOut_($index_) + + $snoopDrop_($index_) target [$drophead_($index_) target] + $drophead_($index_) target $snoopDrop_($index_) + + set bytesInt_($index_) [new Integrator] + $qMonitor_($index_) set-bytes-integrator $bytesInt_($index_) + + set pktsInt_($index_) [new Integrator] + $qMonitor_($index_) set-pkts-integrator $pktsInt_($index_) + + $requester_ set qMonitor_ $qMonitor_($index_) + + $snoopIn_($index_) set-monitor $qMonitor_($index_) + $snoopOut_($index_) set-monitor $qMonitor_($index_) + $snoopDrop_($index_) set-monitor $qMonitor_($index_) +} + + +Node/SatNode instproc install-requester { type {index_ 0} } { + $self instvar mac_ requester_ ifq_ qMonitor_ id_ + + set qMonitor_($index_) [new QueueMonitor] + if {[info exist mac_($index_)]} { + set requester_ [new $type] + $requester_ attach $mac_($index_) + $requester_ setifq $ifq_($index_) + $requester_ set ifq_ $ifq_($index_) + $requester_ set id_ $id_ + $requester_ set node_ $self + $self insert-monitor $index_ + } + $requester_ setmon $qMonitor_($index_) + return $requester_ +} + +Node/SatNode instproc install-allocator {type {index_ 0} } { + $self instvar mac_ allocator_ + if {[info exist mac_($index_)]} { + set allocator_ [new $type] + $allocator_ attach $mac_($index_) + } + return $allocator_ +} + +Node/SatNode instproc trace-event { filedes {index_ 0}} { + $self instvar mac_ et_ + if {[info exist mac_($index_)]} { + set et_ [new BaseTrace/Event] + $et_ attach $filedes + $mac_($index_) eventtrace $et_ + } + return $et_ +} + +Allocator/Tcl instproc initvar { } { + # nothing +} + +Allocator/Tcl instproc allocation { } { + puts stderr "warning: allocation function undefined" + exit +} + +Requester/Tcl instproc initvar { } { + #nothing +} + +Requester/Tcl instproc dorequest { } { + puts stderr "warning: dorequest function undefined" + exit +} ########### # TRACE MODIFICATIONS @@ -804,3 +886,15 @@ Agent/SatRoute set myaddr_ 0 ;# My address Mac/Sat set bandwidth_ 2Mb +Allocator/Proportional set delay_ 1.6 +Allocator/Proportional set active_node_ 0 +Allocator/Proportional set max_slot_num_ 64 + +Allocator/Tcl set delay_ 1.6 +Allocator/Tcl set active_node_ 0 +Allocator/Tcl set max_slot_num_ 64 + +Requester/Constant set request_ 1; +Requester/RBDC set request_ 1; +Requester/VBDC set request_ 1; +Requester/Tcl set request_ 1;
skip to main |
skip to sidebar
Wednesday, April 16, 2008
Tdma-dama patch for ns-2.32
Blog Archive
-
▼
2008
(105)
-
▼
April
(17)
- Epoch/Unix time to normal time
- Changing wine font dpi
- Prothom-alo on Ubuntu/Debian
- My SuPeR-DuPeR vim config ;)
- My konqueror tweaks
- Remove empty lines with Sed
- Read a file line-by-line in Bash
- Installing sun-java on Debian/Etch
- Compiling hotspotter on Kubuntu/Ubuntu 7.10
- Tdma-dama patch for ns-2.32
- Installing Tile/tcl on ubuntu
- Sed, Grep, Awk Tutorials
- Pattern matching with sed
- I Carry Your Heart With Me
- Foxtel iQ info
- Change partition volume labels on linux
- Force dhcp to renew ip address with dhclient
-
▼
April
(17)
Labels
- amarok (2)
- android (4)
- antitaint (1)
- apache (1)
- apple trailers (1)
- apple tv (5)
- ati (2)
- avimerge (1)
- awk (8)
- bash (29)
- batch (1)
- bios (1)
- bittorrent (2)
- blah (1)
- bug (2)
- c (3)
- c++ (1)
- captcha (3)
- chromium (1)
- cityrail (3)
- clipboard (1)
- compiz (3)
- console (1)
- crystal hd (1)
- dccp (2)
- debian (18)
- dhcp (1)
- dictionary (2)
- dns (2)
- dokuwiki (1)
- dpkg (4)
- elitebook (1)
- epoch-time (1)
- epstopdf (1)
- evince (1)
- extract (1)
- fat32 (1)
- ffmpeg (2)
- fileserve (1)
- firefox (9)
- flurry (1)
- font (2)
- foxtel (1)
- funny (1)
- gdb (2)
- gmail (1)
- gnome (1)
- gnuplot (4)
- google-chrome (1)
- greasemonkey (1)
- grep (1)
- gtk (1)
- h264 (2)
- highlight (2)
- hotfile (1)
- hotkey (1)
- hotmail (1)
- hotspotter (1)
- hp (1)
- image-manipulation (3)
- initrd (1)
- iso (1)
- java (3)
- jelly bean (1)
- kernel (1)
- keyboard (1)
- klog (1)
- konqueror (1)
- ktorrent (1)
- laptop (1)
- latex (7)
- lcd (1)
- lightdm (1)
- linux (39)
- lubuntu (3)
- lxde (1)
- lyrics (4)
- lyx (2)
- mac (1)
- mangafox (1)
- miktex (2)
- mkv (2)
- monitor (1)
- mplayer (3)
- netgear (1)
- ns2 (2)
- onemanga (1)
- open-office (1)
- partition (1)
- pastebin (1)
- pdroid (1)
- pennytel (2)
- perl (1)
- php (1)
- pop (1)
- popup (1)
- premiumforfree (1)
- printk (2)
- programming (3)
- prothom-alo (2)
- python (3)
- rapidshare (1)
- real-audio (1)
- reverse-engineering (3)
- screensaver (1)
- sed (6)
- skype (2)
- sms (1)
- ssh (1)
- strace (1)
- swap (1)
- synergy (1)
- taint (1)
- taintdroid (1)
- tcl (1)
- tcpdump (1)
- teleport (1)
- theme (1)
- tshark (3)
- tvshark (1)
- ubuntu (35)
- uuid (1)
- vim (5)
- virtual-box (2)
- vnc (1)
- webmail (2)
- windows (7)
- windows8 (2)
- wine (4)
- wireshark (1)
- word-list (1)
- x11 (3)
- yahoo (1)
0 comments:
Post a Comment