InterfaceTable.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023 #include <algorithm>
00024 #include <sstream>
00025 
00026 #include "InterfaceTable.h"
00027 #include "NotifierConsts.h"
00028 
00029 
00030 Define_Module( InterfaceTable );
00031 
00032 #define INTERFACEIDS_START  100
00033 
00034 std::ostream& operator<<(std::ostream& os, const InterfaceEntry& e)
00035 {
00036     os << e.info();
00037     return os;
00038 };
00039 
00040 
00041 InterfaceTable::InterfaceTable()
00042 {
00043     tmpNumInterfaces = -1;
00044     tmpInterfaceList = NULL;
00045 }
00046 
00047 InterfaceTable::~InterfaceTable()
00048 {
00049     for (int i=0; i < (int)idToInterface.size(); i++)
00050         delete idToInterface[i];
00051     delete [] tmpInterfaceList;
00052 }
00053 
00054 void InterfaceTable::initialize(int stage)
00055 {
00056     if (stage==0)
00057     {
00058         // get a pointer to the NotificationBoard module
00059         nb = NotificationBoardAccess().get();
00060 
00061         // register a loopback interface
00062         InterfaceEntry *ie = new InterfaceEntry();
00063         ie->setName("lo0");
00064         ie->setMtu(3924);
00065         ie->setLoopback(true);
00066         addInterface(ie, NULL);
00067     }
00068     else if (stage==1)
00069     {
00070         WATCH_PTRVECTOR(idToInterface);
00071         updateDisplayString();
00072     }
00073 }
00074 
00075 void InterfaceTable::updateDisplayString()
00076 {
00077     if (!ev.isGUI())
00078         return;
00079 
00080     char buf[80];
00081     sprintf(buf, "%d interfaces", getNumInterfaces());
00082     getDisplayString().setTagArg("t",0,buf);
00083 }
00084 
00085 void InterfaceTable::handleMessage(cMessage *msg)
00086 {
00087     opp_error("This module doesn't process messages");
00088 }
00089 
00090 void InterfaceTable::receiveChangeNotification(int category, const cPolymorphic *details)
00091 {
00092     // nothing needed here at the moment
00093     Enter_Method_Silent();
00094     printNotificationBanner(category, details);
00095 }
00096 
00097 //---
00098 
00099 int InterfaceTable::getNumInterfaces()
00100 {
00101     if (tmpNumInterfaces == -1)
00102     {
00103         // count non-NULL elements
00104         int n = 0;
00105         int maxId = idToInterface.size();
00106         for (int i=0; i<maxId; i++)
00107             if (idToInterface[i])
00108                 n++;
00109         tmpNumInterfaces = n;
00110     }
00111 
00112     return tmpNumInterfaces;
00113 }
00114 
00115 InterfaceEntry *InterfaceTable::getInterface(int pos)
00116 {
00117     int n = getNumInterfaces(); // also fills tmpInterfaceList
00118     if (pos<0 || pos>=n)
00119         opp_error("getInterface(): interface index %d out of range 0..%d", pos, n-1);
00120 
00121     if (!tmpInterfaceList)
00122     {
00123         // collect non-NULL elements into tmpInterfaceList[]
00124         tmpInterfaceList = new InterfaceEntry *[n];
00125         int k = 0;
00126         int maxId = idToInterface.size();
00127         for (int i=0; i<maxId; i++)
00128             if (idToInterface[i])
00129                 tmpInterfaceList[k++] = idToInterface[i];
00130     }
00131 
00132     return tmpInterfaceList[pos];
00133 }
00134 
00135 InterfaceEntry *InterfaceTable::getInterfaceById(int id)
00136 {
00137     id -= INTERFACEIDS_START;
00138     return (id<0 || id>=(int)idToInterface.size()) ? NULL : idToInterface[id];
00139 }
00140 
00141 void InterfaceTable::addInterface(InterfaceEntry *entry, cModule *ifmod)
00142 {
00143     // check name is unique
00144     if (getInterfaceByName(entry->getName())!=NULL)
00145         opp_error("addInterface(): interface '%s' already registered", entry->getName());
00146 
00147     // insert
00148     entry->setInterfaceId(INTERFACEIDS_START + idToInterface.size());
00149     entry->setInterfaceTable(this);
00150     idToInterface.push_back(entry);
00151     invalidateTmpInterfaceList();
00152 
00153     // fill in networkLayerGateIndex, nodeOutputGateId, nodeInputGateId
00154     if (ifmod)
00155         discoverConnectingGates(entry, ifmod);
00156 
00157     nb->fireChangeNotification(NF_INTERFACE_CREATED, entry);
00158 }
00159 
00160 void InterfaceTable::discoverConnectingGates(InterfaceEntry *entry, cModule *ifmod)
00161 {
00162     // ifmod is something like "host.eth[1].mac"; climb up to find "host.eth[1]" from it
00163     cModule *host = getParentModule();
00164     while (ifmod && ifmod->getParentModule()!=host)
00165         ifmod = ifmod->getParentModule();
00166     if (!ifmod)
00167         opp_error("addInterface(): specified module is not in this host/router");
00168 
00169     // find gates connected to host / network layer
00170     cGate *nwlayerInGate=NULL, *nwlayerOutGate=NULL;
00171     for (GateIterator i(ifmod); !i.end(); i++)
00172     {
00173         cGate *g = i();
00174         if (!g) continue;
00175 
00176         // find the host/router's gates that internally connect to this interface
00177         if (g->getType()==cGate::OUTPUT && g->getNextGate() && g->getNextGate()->getOwnerModule()==host)
00178             entry->setNodeOutputGateId(g->getNextGate()->getId());
00179         if (g->getType()==cGate::INPUT && g->getPreviousGate() && g->getPreviousGate()->getOwnerModule()==host)
00180             entry->setNodeInputGateId(g->getPreviousGate()->getId());
00181 
00182         // find the gate index of networkLayer/networkLayer6/mpls that connects to this interface
00183         if (g->getType()==cGate::OUTPUT && g->getNextGate() && g->getNextGate()->isName("ifIn"))
00184             nwlayerInGate = g->getNextGate();
00185         if (g->getType()==cGate::INPUT && g->getPreviousGate() && g->getPreviousGate()->isName("ifOut"))
00186             nwlayerOutGate = g->getPreviousGate();
00187     }
00188 
00189     // consistency checks
00190     // note: we don't check nodeOutputGateId/nodeInputGateId, because wireless interfaces
00191     // are not connected to the host
00192     if (!nwlayerInGate || !nwlayerOutGate || nwlayerInGate->getIndex()!=nwlayerOutGate->getIndex())
00193         opp_error("addInterface(): interface must be connected to network layer's ifIn[]/ifOut[] gates of the same index");
00194     entry->setNetworkLayerGateIndex(nwlayerInGate->getIndex());
00195 }
00196 
00197 void InterfaceTable::deleteInterface(InterfaceEntry *entry)
00198 {
00199     int id = entry->getInterfaceId();
00200     if (entry != getInterfaceById(id))
00201         opp_error("deleteInterface(): interface '%s' not found in interface table", entry->getName());
00202 
00203     nb->fireChangeNotification(NF_INTERFACE_DELETED, entry);  // actually, only going to be deleted
00204 
00205     idToInterface[id - INTERFACEIDS_START] = NULL;
00206     delete entry;
00207     invalidateTmpInterfaceList();
00208 }
00209 
00210 void InterfaceTable::invalidateTmpInterfaceList()
00211 {
00212     tmpNumInterfaces = -1;
00213     delete[] tmpInterfaceList;
00214     tmpInterfaceList = NULL;
00215 }
00216 
00217 void InterfaceTable::interfaceChanged(InterfaceEntry *entry, int category)
00218 {
00219     nb->fireChangeNotification(category, entry);
00220 }
00221 
00222 InterfaceEntry *InterfaceTable::getInterfaceByNodeOutputGateId(int id)
00223 {
00224     // linear search is OK because normally we have don't have many interfaces and this func is rarely called
00225     Enter_Method_Silent();
00226     int n = idToInterface.size();
00227     for (int i=0; i<n; i++)
00228         if (idToInterface[i] && idToInterface[i]->getNodeOutputGateId()==id)
00229             return idToInterface[i];
00230     return NULL;
00231 }
00232 
00233 InterfaceEntry *InterfaceTable::getInterfaceByNodeInputGateId(int id)
00234 {
00235     // linear search is OK because normally we have don't have many interfaces and this func is rarely called
00236     Enter_Method_Silent();
00237     int n = idToInterface.size();
00238     for (int i=0; i<n; i++)
00239         if (idToInterface[i] && idToInterface[i]->getNodeInputGateId()==id)
00240             return idToInterface[i];
00241     return NULL;
00242 }
00243 
00244 InterfaceEntry *InterfaceTable::getInterfaceByNetworkLayerGateIndex(int index)
00245 {
00246     // linear search is OK because normally we have don't have many interfaces and this func is rarely called
00247     Enter_Method_Silent();
00248     int n = idToInterface.size();
00249     for (int i=0; i<n; i++)
00250         if (idToInterface[i] && idToInterface[i]->getNetworkLayerGateIndex()==index)
00251             return idToInterface[i];
00252     return NULL;
00253 }
00254 
00255 InterfaceEntry *InterfaceTable::getInterfaceByName(const char *name)
00256 {
00257     Enter_Method_Silent();
00258     if (!name)
00259         return NULL;
00260     int n = idToInterface.size();
00261     for (int i=0; i<n; i++)
00262         if (idToInterface[i] && !strcmp(name, idToInterface[i]->getName()))
00263             return idToInterface[i];
00264     return NULL;
00265 }
00266 
00267 InterfaceEntry *InterfaceTable::getFirstLoopbackInterface()
00268 {
00269     Enter_Method_Silent();
00270     int n = idToInterface.size();
00271     for (int i=0; i<n; i++)
00272         if (idToInterface[i] && idToInterface[i]->isLoopback())
00273             return idToInterface[i];
00274     return NULL;
00275 }
00276