lms-agent.cc

Go to the documentation of this file.
00001 
00002 /*
00003  * lms-agent.cc
00004  * Copyright (C) 2001 by the University of Southern California
00005  * $Id: lms-agent.cc,v 1.3 2005/08/25 18:58:07 johnh Exp $
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00019  *
00020  *
00021  * The copyright of this module includes the following
00022  * linking-with-specific-other-licenses addition:
00023  *
00024  * In addition, as a special exception, the copyright holders of
00025  * this module give you permission to combine (via static or
00026  * dynamic linking) this module with free software programs or
00027  * libraries that are released under the GNU LGPL and with code
00028  * included in the standard release of ns-2 under the Apache 2.0
00029  * license or under otherwise-compatible licenses with advertising
00030  * requirements (or modified versions of such code, with unchanged
00031  * license).  You may copy and distribute such a system following the
00032  * terms of the GNU GPL for this module and the licenses of the
00033  * other code concerned, provided that you include the source code of
00034  * that other code when and as the GNU GPL requires distribution of
00035  * source code.
00036  *
00037  * Note that people who make modified versions of this module
00038  * are not obligated to grant this special exception for their
00039  * modified versions; it is their choice whether to do so.  The GNU
00040  * General Public License gives permission to release a modified
00041  * version without this exception; this exception also makes it
00042  * possible to release a modified version which carries forward this
00043  * exception.
00044  *
00045  */
00046 
00047 /*
00048  * Light-Weight Multicast Services (LMS), Reliable Multicast
00049  *
00050  * lms-agent.cc
00051  *
00052  * This implements the network element LMS agent, "Agent/LMS".
00053  *
00054  * Christos Papadopoulos. 
00055  * christos@isi.edu
00056  */
00057 
00058 #include <assert.h>
00059 
00060 #include "agent.h"
00061 #include "tclcl.h"
00062 #include "packet.h"
00063 #include "random.h"
00064 #include "lms.h"
00065 #include "ip.h"
00066 
00067 static int lms_agent_uid_ = 0;  // each LMS agent has a uid
00068 
00069 class LmsAgent : public Agent {
00070  public:
00071     LmsAgent ();
00072     int command (int argc, const char*const* argv);
00073     void    recv (Packet*, Handler*);
00074  protected:
00075     //inline int    off_lms() { return off_lms_; };
00076     NsObject*   iface2link (int iface);
00077     NsObject*   pkt2agent (Packet *pkt);
00078     void        send_upstream (Packet *p);
00079         void            send_downstream (Packet *p);
00080 
00081         inline void
00082      send2replier (Packet *p)
00083         {
00084         hdr_ip* piph = HDR_IP(p);
00085         //hdr_cmn* c = HDR_CMN(p);
00086 #ifdef LMS_DEBUG
00087 printf("%s send2replier: Got piph->saddr: %d, downstream_addr: %d. Replier: %d\n", uname_, piph->saddr(), downstream_lms_.addr_, replier_ );
00088 #endif
00089         if (replier_ != NULL)
00090             replier_->recv (p);
00091         else if ((downstream_lms_.addr_ != LMS_NOADDR) &&
00092              (piph->saddr() != downstream_lms_.addr_) )
00093             send_downstream(p);
00094         else    send_upstream (p); 
00095         };
00096 
00097     char    uname_[16]; // agent's unique name
00098     int lms_enabled_;   // is this agent enabled? Default is YES
00099     NsObject* replier_; // agent's replier (link or receiver)
00100     int replier_iface_; // replier interface (-2 if replier is local)
00101     int replier_cost_;  // replier cost
00102     int replier_dist_;  // replier distance, in #of hops
00103     nsaddr_t upstream_lms_; // upstream LMS entity
00104     ns_addr_t downstream_lms_;// needed for incr.deployment
00105     
00106     int upstream_iface_;// upstream interface (-2 if source is local)
00107     int have_rcvr_; // flag the presence of a receiver on this node
00108 
00109     // Header offsets
00110     // int  off_ip_;
00111     // int  off_lms_;
00112 };
00113 
00114 //
00115 // Declaration of Agent/LMS
00116 //
00117 static class LmsClass : public TclClass {
00118 public:
00119     LmsClass() : TclClass("Agent/LMS") {}
00120     TclObject* create(int, const char*const*) {
00121         return (new LmsAgent());
00122     }
00123 } class_lms_agent;
00124 
00125 
00126 //
00127 // Declaration of PacketHeader/Lms
00128 //
00129 
00130 int hdr_lms::offset_;
00131 
00132 static class LmsHeaderClass : public PacketHeaderClass {
00133 public:
00134         LmsHeaderClass() : PacketHeaderClass("PacketHeader/Lms",
00135                          sizeof(hdr_lms)) {
00136         bind_offset(&hdr_lms::offset_);
00137     }
00138 } class_lmshdr;
00139 
00140 
00141 //
00142 // Initialization routine
00143 //
00144 LmsAgent::LmsAgent() : Agent(PT_LMS)
00145 {
00146     sprintf (uname_, "lms%d", lms_agent_uid_++);
00147     replier_  = NULL;
00148     replier_iface_ = LMS_NOIFACE;
00149     replier_cost_  = LMS_INFINITY;
00150     replier_dist_  = 0;
00151     upstream_lms_  = LMS_NOADDR;
00152     downstream_lms_.addr_ = LMS_NOADDR;
00153     downstream_lms_.port_ = LMS_NOPORT;
00154     have_rcvr_ = 0;
00155 
00156     bind("lms_enabled_", &lms_enabled_);
00157     bind("packetSize_", &size_);
00158     // bind("off_ip_", &off_ip_);
00159     // bind("off_lms_", &off_lms_);
00160 }
00161 
00162 //
00163 // Main LMS receive function
00164 //
00165 void LmsAgent::recv (Packet* pkt, Handler*)
00166 {
00167     hdr_cmn* h = HDR_CMN(pkt);
00168     hdr_lms* lh = HDR_LMS(pkt);
00169     //    double now = Scheduler::instance().clock();
00170     
00171 #ifdef LMS_DEBUG
00172 int a1 = lh->from_; int a2 = lh->src_;
00173 printf ("at %f %s received packet type %d from %d:%d src %d:%d group %x iface %d\n\n", now,uname_, lh->type(), a1>>8, a1&0xff, a2>>8, a2&0xff, lh->group_,h->iface());
00174 #endif
00175 
00176     // if this agent is not enabled, simply pass on the packet
00177     if (!lms_enabled_)
00178         {
00179         target_->recv (pkt);
00180         return;
00181         }
00182 
00183     switch (lh->type())
00184     {
00185          case LMS_SRC_REFRESH:
00186         {
00187         // If we have a replier already, and the upstream adv cost
00188         // is less than our current cost and the upstream distance
00189         // is less than our current distance, then choose the
00190         // upstream link as the replier link.
00191         struct lms_ctl *c = (struct lms_ctl *)pkt->accessdata ();
00192         c->hop_cnt_++;
00193 #ifdef LMS_DEBUG
00194 printf ("%s LMS_SRC_REFRESH from iface %d, cost %d, ttl %d\n\n",
00195 uname_, h->iface(), c->cost_, lh->ttl_);
00196 #endif
00197                  assert (upstream_iface_ == h->iface());
00198 
00199                  if (replier_iface_ == h->iface())
00200             {
00201             if (replier_cost_ != c->cost_)
00202                 replier_cost_ = c->cost_;
00203             if (replier_dist_ != c->hop_cnt_)
00204                 replier_dist_ = c->hop_cnt_;
00205             }
00206                  else if (replier_cost_ >= c->cost_ && replier_dist_ > c->hop_cnt_)
00207             {
00208 #ifdef LMS_DEBUG
00209 printf ("%s chose upstream replier\n\n", uname_);
00210 #endif
00211             replier_cost_ = c->cost_;
00212             replier_dist_ = c->hop_cnt_;
00213             replier_iface_ = h->iface();
00214             if (h->iface() < 0)
00215                 {
00216                 replier_ = pkt2agent (pkt);
00217                 downstream_lms_.addr_ = LMS_NOADDR;
00218                 downstream_lms_.port_ = LMS_NOPORT;
00219                 }
00220             else    {
00221                 replier_ = iface2link (h->iface());
00222                 downstream_lms_.addr_ = LMS_NOADDR;
00223                 downstream_lms_.port_ = LMS_NOPORT;
00224                 }
00225             if (--lh->ttl_ > 0)
00226                 target_->recv (pkt);
00227             else    Packet::free(pkt);
00228             return;
00229             }
00230                  break;
00231            }
00232            
00233          case LMS_REFRESH:
00234              {
00235                  struct lms_ctl *c = (struct lms_ctl *)pkt->accessdata ();
00236                  c->hop_cnt_++;
00237 #ifdef LMS_DEBUG
00238 printf("%s replier iface %d, h->iface %d, replier cost %d, c cost %d\n",
00239   uname_, replier_iface_, h->iface(), replier_cost_, c->cost_);
00240 printf("replier_= %d, down_addr_= %d, down_port_ = %d\n\n",
00241   replier_, downstream_lms_.addr_, downstream_lms_.port_);
00242 #endif     
00243 
00244                  // update from existing replier
00245                  // adjust cost and distance and send upstream
00246                  if (replier_iface_ == h->iface())
00247                  {
00248                      if (replier_cost_ != c->cost_)
00249                          replier_cost_ = c->cost_;
00250                      if (replier_dist_ != c->hop_cnt_)
00251                          replier_dist_ = c->hop_cnt_;
00252 #ifdef LMS_DEBUG
00253 printf ("%s REPLIER_UPDATE iface %d, cost %d, hops %d\n\n",
00254    uname_, replier_iface_, replier_cost_, replier_dist_);
00255 #endif
00256 
00257     
00258                      if (h->iface() < 0)
00259                      {
00260                          replier_ = pkt2agent (pkt);
00261                          have_rcvr_ = 1;
00262                          downstream_lms_.addr_ = LMS_NOADDR;
00263                          downstream_lms_.port_ = LMS_NOPORT;
00264                      }
00265                      else
00266                      {  
00267                          // updates our entry for downstream_lms_ 
00268                          downstream_lms_ = c->downstream_lms_;
00269                          // places our own address in downstream_lms_
00270                          // before sending it upstream.
00271                          c->downstream_lms_.addr_ = addr();
00272                          c->downstream_lms_.port_ = port();
00273                          
00274                          replier_ = NULL;
00275                      }
00276                      send_upstream (pkt);
00277                  }
00278 
00279                  // found a better replier
00280                  else if (replier_cost_ > c->cost_)
00281                  {
00282                      replier_cost_ = c->cost_;
00283                      replier_dist_ = c->hop_cnt_;
00284                      replier_iface_ = h->iface();
00285                      
00286                      if (h->iface() < 0)
00287                      {
00288                          replier_ = pkt2agent (pkt);
00289                          have_rcvr_ = 1;
00290                          downstream_lms_.addr_ = LMS_NOADDR;
00291                          downstream_lms_.port_ = LMS_NOPORT;
00292                      }
00293                      else
00294                      {  
00295                          // updates our entry for downstream_lms_ 
00296                          downstream_lms_ = c->downstream_lms_;
00297                          // places our own address in downstream_lms_
00298                          // before sending it upstream.
00299                          c->downstream_lms_.addr_ = addr();
00300                          c->downstream_lms_.port_ = port();
00301                                 
00302                          replier_ = NULL;                                    
00303                      }
00304 #ifdef LMS_DEBUG
00305 printf ("%s REPLIER iface %d, cost %d, hops %d\n\n",
00306   uname_, replier_iface_, replier_cost_, replier_dist_);
00307 #endif
00308                      send_upstream (pkt);
00309                  }
00310                  else
00311                      Packet::free(pkt);
00312                  return;
00313              }
00314 
00315      case LMS_REQ:
00316              if (replier_iface_ == h->iface())
00317                  send_upstream (pkt);
00318              else {
00319                  // fill turning point info, but only
00320                  // if no-one else has done so already.
00321                  if (lh->tp_addr_ == LMS_NOADDR)
00322                     {
00323                     lh->tp_addr_  = addr();
00324                     lh->tp_port_  = port();
00325                     lh->tp_iface_ = h->iface_;
00326                     }
00327                  send2replier (pkt);
00328                 }
00329              break;
00330 
00331      case LMS_DMCAST:
00332              {
00333 #ifdef LMS_DEBUG
00334 a2 = lh->src_;
00335 printf ("LMS-DMCAST at agent %s, iface %d src %d:%d group %d\n\n",
00336   uname_, lh->tp_iface_, a2>>8, a2&0xff, lh->group_);
00337 #endif
00338                  hdr_ip* iph = HDR_IP(pkt);
00339                  NsObject* tgt = iface2link (lh->tp_iface_);
00340 
00341                  if (tgt)
00342                  {
00343            //packet_t t = h->ptype();
00344                      iph->saddr() = lh->src_;
00345                      iph->daddr() = lh->group_;
00346                      tgt->recv (pkt);
00347                  }
00348                  else   {
00349                      printf ("FATAL: %s no such iface %d\n", uname_, lh->tp_iface_);
00350                      abort ();
00351                  }
00352              }
00353              break;
00354              
00355          case LMS_LEAVE:
00356              {
00357                  
00358                  if (replier_iface_ == h->iface())
00359                  {
00360                      downstream_lms_.addr_ = LMS_NOADDR;
00361                      downstream_lms_.port_ = LMS_NOPORT;
00362                      
00363                      replier_ = NULL;
00364                      replier_cost_ = 1000000;
00365                      replier_iface_ = LMS_NOIFACE;
00366                      send_upstream (pkt);
00367                  }
00368                  else
00369                      Packet::free(pkt);
00370                  
00371                  return;
00372              }
00373              
00374          case LMS_SETUP:
00375              {
00376                  
00377                  if (h->iface() < 0)
00378                  {
00379                      // Source is attached - mark it as the replier
00380                      replier_ = pkt2agent (pkt);
00381                      replier_iface_ = h->iface();
00382                      downstream_lms_.addr_ = LMS_NOADDR;
00383                      downstream_lms_.port_ = LMS_NOPORT;
00384                      
00385                      replier_cost_ = 0;     // XXX
00386                      
00387 #ifdef LMS_DEBUG
00388 printf ("%s REPLIER iface %d, cost %d\n\n", uname_, replier_iface_, replier_cost_);
00389 #endif
00390 
00391                  }
00392                  upstream_lms_ = lh->from_;
00393                  upstream_iface_ = h->iface();
00394                  
00395 #ifdef LMS_DEBUG    
00396 printf ("%s upstream %d\n\n", uname_, upstream_lms_);
00397 #endif
00398  
00399                  lh->from_ = addr();
00400                  Tcl::instance().evalf("[%s set node_] agent %d", name(), port());
00401                  target_->recv (pkt);
00402                  return;
00403              }
00404              
00405          case LMS_SPM:
00406              {
00407                  if (upstream_lms_ < 0)
00408                  {
00409                      struct lms_spm *spm = (struct lms_spm *)pkt->accessdata ();
00410                      //nsaddr_t adr = spm->spm_path_;
00411 #ifdef LMS_DEBUG    
00412 printf ("%s LMS_SPM seqno %d, upstream %d:%d\n\n",
00413   uname_, spm->spm_seqno_, adr>>8, adr&0xff);
00414 #endif
00415 
00416                       if (upstream_lms_ != spm->spm_path_)
00417                           upstream_lms_ = spm->spm_path_;
00418 
00419                       spm->spm_path_ = addr();
00420                  }
00421                  break;
00422              }
00423              
00424      case LMS_LINKS:
00425              {
00426                  Tcl& tcl = Tcl::instance();
00427                  char wrk[64];
00428                  int  n1 = lh->from();
00429                  int  n2 = addr();
00430                  
00431                  if (n1 != n2 && !have_rcvr_)
00432                  {
00433                      sprintf (wrk, "lappend tree_links {%d %d}", n1, n2);
00434                      tcl.eval (wrk);
00435                  }
00436                  
00437                  lh->from_ = addr();
00438                  target_->recv (pkt);
00439                  return;
00440              }
00441          default:
00442              printf ("FATAL: %s uknown LMS packet type: %d\n", uname_, lh->type());
00443              abort ();
00444      }          
00445 }
00446 
00447      
00448 
00449 int LmsAgent::command (int argc, const char*const* argv)
00450 {
00451   //Tcl& tcl = Tcl::instance();
00452 
00453     if (argc == 6) {
00454         if (strcmp(argv[1], "send-lms") == 0) {
00455             Packet* pkt = allocpkt();
00456             hdr_lms* ph = HDR_LMS(pkt);
00457 
00458             ph->type() = atoi (argv[2]);
00459             ph->from() = atoi(argv[3]);
00460             ph->src() = atoi(argv[4]);
00461             ph->group() = atoi(argv[5]);
00462 
00463             send(pkt, 0);
00464             return (TCL_OK);
00465         }
00466     }
00467         
00468     return (Agent::command(argc, argv));
00469 }
00470 
00471 
00472 /*
00473  * Given an interface number,
00474  * return its outgoing link
00475  */
00476 NsObject* LmsAgent::iface2link (int iface)
00477 {
00478     Tcl&    tcl = Tcl::instance();
00479     char    wrk[64];
00480 
00481     sprintf (wrk, "[%s set node_] ifaceGetOutLink %d", name (), iface);
00482     tcl.evalc (wrk);
00483     const char* result = tcl.result ();
00484 
00485 #ifdef LMS_DEBUG
00486 printf ("[iface2link] agent %s\n", result);
00487 #endif
00488 
00489     NsObject* obj = (NsObject*)TclObject::lookup(result);
00490     return (obj);
00491 }
00492 
00493 /*
00494  * Given a packet, determine which agent sent it
00495  * Agent MUST be attached to this node
00496  */
00497 NsObject* LmsAgent::pkt2agent (Packet *pkt)
00498 {
00499     Tcl&        tcl = Tcl::instance();
00500     char        wrk[64];
00501     const char      *result;
00502     int     port;
00503     NsObject*   agent;
00504     hdr_ip*     ih = HDR_IP(pkt);
00505     //nsaddr_t  src = ih->saddr();
00506 
00507     port = ih->sport();
00508 
00509     sprintf (wrk, "[%s set node_] agent %d", name (), port);
00510     tcl.evalc (wrk);
00511     result = tcl.result ();
00512 
00513 #ifdef LMS_DEBUG
00514 printf ("[pkt2agent] port %d, agent %s\n", port, result);
00515 #endif
00516 
00517     agent = (NsObject*)TclObject::lookup (result);
00518     return (agent);
00519 }
00520 
00521 void LmsAgent::send_upstream (Packet *p)
00522 {
00523     if (upstream_lms_ < 0)
00524         {
00525         printf ("FATAL: %s upstream_lms_ not set!\n", uname_);
00526         abort ();
00527         }
00528     hdr_ip* ih = HDR_IP(p);
00529     hdr_lms* lh = HDR_LMS(p);
00530 
00531     lh->from_ = addr();
00532     ih->daddr() = upstream_lms_;
00533     target_->recv(p);
00534 }
00535 
00536 
00537 void LmsAgent::send_downstream (Packet *p)
00538 {
00539     if (downstream_lms_.addr_ < 0)
00540     {
00541         printf ("FATAL: %s downstream_lms_ not set!\n", uname_);
00542         abort ();
00543     }
00544     hdr_ip* ih = HDR_IP(p);
00545     hdr_lms* lh = HDR_LMS(p);
00546     
00547     lh->from_ = addr();
00548     ih->daddr() = downstream_lms_.addr_;
00549     ih->dport() = downstream_lms_.port_;
00550     
00551     target_->recv(p);
00552 }

Generated on Tue Mar 6 16:47:46 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6