INET Framework for OMNeT++/OMNEST
LDP Class Reference

#include <LDP.h>

Inheritance diagram for LDP:
TCPSocket::CallbackInterface IClassifier INotifiable

List of all members.

Classes

struct  fec_bind_t
struct  fec_t
struct  peer_info
struct  pending_req_t

Public Types

typedef std::vector< fec_tFecVector
typedef std::vector< fec_bind_tFecBindVector
typedef std::vector
< pending_req_t
PendingVector
typedef std::vector< peer_infoPeerVector

Public Member Functions

 LDP ()
virtual ~LDP ()

Protected Member Functions

virtual IPAddress locateNextHop (IPAddress dest)
virtual IPAddress findPeerAddrFromInterface (std::string interfaceName)
std::string findInterfaceFromPeerAddr (IPAddress peerIP)
virtual int findPeer (IPAddress peerAddr)
virtual TCPSocketgetPeerSocket (IPAddress peerAddr)
virtual TCPSocketfindPeerSocket (IPAddress peerAddr)
virtual void sendToPeer (IPAddress dest, cMessage *msg)
FecVector::iterator findFecEntry (FecVector &fecs, IPAddress addr, int length)
FecBindVector::iterator findFecEntry (FecBindVector &fecs, int fecid, IPAddress peer)
virtual void sendMappingRequest (IPAddress dest, IPAddress addr, int length)
virtual void sendMapping (int type, IPAddress dest, int label, IPAddress addr, int length)
virtual void sendNotify (int status, IPAddress dest, IPAddress addr, int length)
virtual void rebuildFecList ()
virtual void updateFecList (IPAddress nextHop)
virtual void updateFecListEntry (fec_t oldItem)
virtual void announceLinkChange (int tedlinkindex)
virtual int numInitStages () const
virtual void initialize (int stage)
virtual void handleMessage (cMessage *msg)
virtual void sendHelloTo (IPAddress dest)
virtual void openTCPConnectionToPeer (int peerIndex)
virtual void processLDPHello (LDPHello *msg)
virtual void processHelloTimeout (cMessage *msg)
virtual void processMessageFromTCP (cMessage *msg)
virtual void processLDPPacketFromTCP (LDPPacket *ldpPacket)
virtual void processLABEL_MAPPING (LDPLabelMapping *packet)
virtual void processLABEL_REQUEST (LDPLabelRequest *packet)
virtual void processLABEL_RELEASE (LDPLabelMapping *packet)
virtual void processLABEL_WITHDRAW (LDPLabelMapping *packet)
virtual void processNOTIFICATION (LDPNotify *packet)
virtual bool lookupLabel (IPDatagram *ipdatagram, LabelOpVector &outLabel, std::string &outInterface, int &color)
virtual void receiveChangeNotification (int category, const cPolymorphic *details)
TCPSocket::CallbackInterface callback methods
virtual void socketEstablished (int connId, void *yourPtr)
virtual void socketDataArrived (int connId, void *yourPtr, cPacket *msg, bool urgent)
virtual void socketPeerClosed (int connId, void *yourPtr)
virtual void socketClosed (int connId, void *yourPtr)
virtual void socketFailure (int connId, void *yourPtr, int code)
virtual void socketStatusArrived (int connId, void *yourPtr, TCPStatusInfo *status)

Protected Attributes

simtime_t holdTime
simtime_t helloInterval
FecVector fecList
FecBindVector fecUp
FecBindVector fecDown
PendingVector pending
PeerVector myPeers
IInterfaceTableift
IRoutingTablert
LIBTablelt
TEDtedmod
NotificationBoardnb
UDPSocket udpSocket
TCPSocket serverSocket
TCPSocketMap socketMap
cMessage * sendHelloMsg
int maxFecid

Detailed Description

LDP (rfc 3036) protocol implementation.


Member Typedef Documentation

typedef std::vector<fec_bind_t> LDP::FecBindVector
typedef std::vector<fec_t> LDP::FecVector
typedef std::vector<peer_info> LDP::PeerVector
typedef std::vector<pending_req_t> LDP::PendingVector

Constructor & Destructor Documentation

LDP::LDP ( )
{
    sendHelloMsg = NULL;
}
LDP::~LDP ( ) [virtual]
{
    for (unsigned int i=0; i<myPeers.size(); i++)
        cancelAndDelete(myPeers[i].timeout);

    cancelAndDelete(sendHelloMsg);
    //this causes segfault at the end of simulation       -- Vojta
    //socketMap.deleteSockets();
}

Member Function Documentation

void LDP::announceLinkChange ( int  tedlinkindex) [protected, virtual]

Referenced by processHelloTimeout(), and processLDPHello().

{
    TEDChangeInfo d;
    d.setTedLinkIndicesArraySize(1);
    d.setTedLinkIndices(0, tedlinkindex);
    nb->fireChangeNotification(NF_TED_CHANGED, &d);
}
LDP::FecVector::iterator LDP::findFecEntry ( FecVector fecs,
IPAddress  addr,
int  length 
) [protected]

Referenced by lookupLabel(), processLABEL_MAPPING(), processLABEL_RELEASE(), processLABEL_REQUEST(), processLABEL_WITHDRAW(), processNOTIFICATION(), rebuildFecList(), and updateFecListEntry().

{
    FecVector::iterator it;
    for (it = fecs.begin(); it != fecs.end(); it++)
    {
        if (it->length != length)
            continue;

        if (it->addr != addr) // XXX compare only relevant part (?)
            continue;

        break;
    }
    return it;
}
LDP::FecBindVector::iterator LDP::findFecEntry ( FecBindVector fecs,
int  fecid,
IPAddress  peer 
) [protected]
{
    FecBindVector::iterator it;
    for (it = fecs.begin(); it != fecs.end(); it++)
    {
        if (it->fecid != fecid)
            continue;

        if (it->peer != peer)
            continue;

        break;
    }
    return it;
}
std::string LDP::findInterfaceFromPeerAddr ( IPAddress  peerIP) [protected]

Referenced by lookupLabel(), processLABEL_MAPPING(), processLABEL_REQUEST(), and updateFecListEntry().

{
/*
    int i;
    for (unsigned int i=0;i<myPeers.size();i++)
    {
        if (myPeers[i].peerIP == peerIP)
            return string(myPeers[i].linkInterface);
    }
    return string("X");
*/
//    Rely on port index to find the interface name

    // this function is a misnomer, we must recognize our own address too
    if (rt->isLocalAddress(peerIP))
        return "lo0";

    InterfaceEntry *ie = rt->getInterfaceForDestAddr(peerIP);
    if (!ie)
        error("findInterfaceFromPeerAddr(): %s is not routable", peerIP.str().c_str());
    return ie->getName();
}
int LDP::findPeer ( IPAddress  peerAddr) [protected, virtual]

Utility: return peer's index in myPeers table, or -1 if not found

Referenced by findPeerSocket(), processLDPHello(), and processMessageFromTCP().

{
    for (PeerVector::iterator i=myPeers.begin(); i!=myPeers.end(); ++i)
        if (i->peerIP==peerAddr)
            return i-myPeers.begin();
    return -1;
}
IPAddress LDP::findPeerAddrFromInterface ( std::string  interfaceName) [protected, virtual]

This method maps the peerIP with the interface name in routing table. It is expected that for MPLS host, entries linked to MPLS peers are available. In case no corresponding peerIP found, a peerIP (not deterministic) will be returned.

Referenced by locateNextHop().

{
    int i = 0;
    int k = 0;
    InterfaceEntry *ie = ift->getInterfaceByName(interfaceName.c_str());

    const IPRoute *anEntry;

    for (i = 0; i < rt->getNumRoutes(); i++)
    {
        for (k = 0; k < (int)myPeers.size(); k++)
        {
            anEntry = rt->getRoute(i);
            if (anEntry->getHost()==myPeers[k].peerIP && anEntry->getInterface()==ie)
            {
                return myPeers[k].peerIP;
            }
            // addresses->push_back(peerIP[k]);
        }
    }

    // Return any IP which has default route - not in routing table entries
    for (i = 0; i < (int)myPeers.size(); i++)
    {
        for (k = 0; k < rt->getNumRoutes(); k++)
        {
            anEntry = rt->getRoute(i);
            if (anEntry->getHost() == myPeers[i].peerIP)
                break;
        }
        if (k == rt->getNumRoutes())
            break;
    }

    // return the peer's address if found, unspecified address otherwise
    return i==(int)myPeers.size() ? IPAddress() : myPeers[i].peerIP;
}
TCPSocket * LDP::findPeerSocket ( IPAddress  peerAddr) [protected, virtual]

Utility: return socket for given peer, and NULL if session doesn't exist

Referenced by getPeerSocket(), processLABEL_REQUEST(), and updateFecListEntry().

{
    // find peer in table and return its socket
    int i = findPeer(peerAddr);
    if (i==-1 || !(myPeers[i].socket) || myPeers[i].socket->getState()!=TCPSocket::CONNECTED)
        return NULL; // we don't have an LDP session to this peer
    return myPeers[i].socket;
}
TCPSocket * LDP::getPeerSocket ( IPAddress  peerAddr) [protected, virtual]

Utility: return socket for given peer. Throws error if there's no TCP connection

Referenced by sendToPeer().

{
    TCPSocket *sock = findPeerSocket(peerAddr);
    ASSERT(sock);
    if (!sock)
        error("No LDP session to peer %s yet", peerAddr.str().c_str());
    return sock;
}
void LDP::handleMessage ( cMessage *  msg) [protected, virtual]
{
    EV << "Received: (" << msg->getClassName() << ")" << msg->getName() << "\n";
    if (msg==sendHelloMsg)
    {
        // every LDP capable router periodically sends HELLO messages to the
        // "all routers in the sub-network" multicast address
        EV << "Multicasting LDP Hello to neighboring routers\n";
        sendHelloTo(IPAddress::ALL_ROUTERS_MCAST);

        // schedule next hello
        scheduleAt(simTime() + helloInterval, sendHelloMsg);
    }
    else if (msg->isSelfMessage())
    {
        EV << "Timer " << msg->getName() << " expired\n";
        if (!strcmp(msg->getName(), "HelloTimeout"))
        {
            processHelloTimeout(msg);
        }
        else
        {
            processNOTIFICATION(check_and_cast<LDPNotify*>(msg));
        }
    }
    else if (!strcmp(msg->getArrivalGate()->getName(), "udpIn"))
    {
        // we can only receive LDP Hello from UDP (everything else goes over TCP)
        processLDPHello(check_and_cast<LDPHello *>(msg));
    }
    else if (!strcmp(msg->getArrivalGate()->getName(), "tcpIn"))
    {
        processMessageFromTCP(msg);
    }
}
void LDP::initialize ( int  stage) [protected, virtual]
{
    if (stage != 3)
        return; // wait for routing table to initialize first

    holdTime = par("holdTime").doubleValue();
    helloInterval = par("helloInterval").doubleValue();

    ift = InterfaceTableAccess().get();
    rt = RoutingTableAccess().get();
    lt = LIBTableAccess().get();
    tedmod = TEDAccess().get();
    nb = NotificationBoardAccess().get();

    WATCH_VECTOR(myPeers);
    WATCH_VECTOR(fecUp);
    WATCH_VECTOR(fecDown);
    WATCH_VECTOR(fecList);
    WATCH_VECTOR(pending);

    maxFecid = 0;

    // schedule first hello
    sendHelloMsg = new cMessage("LDPSendHello");
    scheduleAt(simTime() + exponential(0.1), sendHelloMsg);

    // bind UDP socket
    udpSocket.setOutputGate(gate("udpOut"));
    udpSocket.bind(LDP_PORT);

    // start listening for incoming TCP conns
    EV << "Starting to listen on port " << LDP_PORT << " for incoming LDP sessions\n";
    serverSocket.setOutputGate(gate("tcpOut"));
    serverSocket.bind(LDP_PORT);
    serverSocket.listen();

    // build list of recognized FECs
    rebuildFecList();

    // listen for routing table modifications
    nb->subscribe(this, NF_IPv4_ROUTE_ADDED);
    nb->subscribe(this, NF_IPv4_ROUTE_DELETED);
}
IPAddress LDP::locateNextHop ( IPAddress  dest) [protected, virtual]

This method finds next peer in upstream direction

{
    // Mapping L3 IP-host of next hop to L2 peer address.

    // Lookup the routing table, rfc3036
    // "When the FEC for which a label is requested is a Prefix FEC Element or
    //  a Host Address FEC Element, the receiving LSR uses its routing table to determine
    //  its response. Unless its routing table includes an entry that exactly matches
    //  the requested Prefix or Host Address, the LSR must respond with a
    //  No Route Notification message."
    //
    // FIXME the code below (though seems like that's what the RFC refers to) doesn't work
    // -- we can't reasonably expect the destination host to be exaplicitly in an
    // LSR's routing table!!! Use simple IP routing instead. --Andras
    //
    // Wrong code:
    //int i;
    //for (i=0; i < rt->getNumRoutes(); i++)
    //    if (rt->getRoute(i)->host == dest)
    //        break;
    //
    //if (i == rt->getNumRoutes())
    //    return IPAddress();  // Signal an NOTIFICATION of NO ROUTE
    //
    InterfaceEntry *ie = rt->getInterfaceForDestAddr(dest);
    if (!ie)
        return IPAddress();  // no route

    std::string iName = ie->getName(); // FIXME why use name for lookup?
    return findPeerAddrFromInterface(iName);
}
bool LDP::lookupLabel ( IPDatagram *  ipdatagram,
LabelOpVector outLabel,
std::string &  outInterface,
int &  color 
) [protected, virtual]

The ipdatagram argument is an input parameter, the rest (outLabel, outInterface, color) are output parameters only.

In subclasses, this function should be implemented to determine the forwarding equivalence class for the IP datagram passed, and map it to an outLabel and outInterface.

The color parameter (which can be set to an arbitrary value) will only be used for the NAM trace if one will be recorded.

Implements IClassifier.

{
    IPAddress destAddr = ipdatagram->getDestAddress();
    int protocol = ipdatagram->getTransportProtocol();

    // never match and always route via L3 if:

    // OSPF traffic (TED)
    if (protocol == IP_PROT_OSPF)
        return false;

    // LDP traffic (both discovery...
    if (protocol == IP_PROT_UDP && check_and_cast<UDPPacket*>(ipdatagram->getEncapsulatedPacket())->getDestinationPort() == LDP_PORT)
        return false;

    // ...and session)
    if (protocol == IP_PROT_TCP && check_and_cast<TCPSegment*>(ipdatagram->getEncapsulatedPacket())->getDestPort() == LDP_PORT)
        return false;
    if (protocol == IP_PROT_TCP && check_and_cast<TCPSegment*>(ipdatagram->getEncapsulatedPacket())->getSrcPort() == LDP_PORT)
        return false;

    // regular traffic, classify, label etc.

    FecVector::iterator it;
    for (it = fecList.begin(); it != fecList.end(); it++)
    {
        if (!destAddr.prefixMatches(it->addr, it->length))
            continue;

        EV << "FEC matched: " << *it << endl;

        FecBindVector::iterator dit = findFecEntry(fecDown, it->fecid, it->nextHop);
        if (dit != fecDown.end())
        {
            outLabel = LIBTable::pushLabel(dit->label);
            outInterface = findInterfaceFromPeerAddr(it->nextHop);
            color = LDP_USER_TRAFFIC;
            EV << "mapping found, outLabel=" << outLabel << ", outInterface=" << outInterface << endl;
            return true;
        }
        else
        {
            EV << "no mapping for this FEC exists" << endl;
            return false;
        }
    }
    return false;
}
virtual int LDP::numInitStages ( ) const [inline, protected, virtual]
{return 4;}
void LDP::openTCPConnectionToPeer ( int  peerIndex) [protected, virtual]

Referenced by processLDPHello().

{
    TCPSocket *socket = new TCPSocket();
    socket->setOutputGate(gate("tcpOut"));
    socket->setCallbackObject(this, (void*)peerIndex);
    socket->bind(rt->getRouterId(), 0);
    socketMap.addSocket(socket);
    myPeers[peerIndex].socket = socket;

    socket->connect(myPeers[peerIndex].peerIP, LDP_PORT);
}
void LDP::processHelloTimeout ( cMessage *  msg) [protected, virtual]

Referenced by handleMessage().

{
    // peer is gone

    unsigned int i;
    for (i = 0; i < myPeers.size(); i++)
        if (myPeers[i].timeout == msg)
            break;
    ASSERT(i < myPeers.size());

    IPAddress peerIP = myPeers[i].peerIP;

    EV << "peer=" << peerIP << " is gone, removing adjacency" << endl;

    ASSERT(!myPeers[i].timeout->isScheduled());
    delete myPeers[i].timeout;
    ASSERT(myPeers[i].socket);
    myPeers[i].socket->abort(); // should we only close?
    delete myPeers[i].socket;
    myPeers.erase(myPeers.begin() + i);

    EV << "removing (stale) bindings from fecDown for peer=" << peerIP << endl;

    FecBindVector::iterator dit;
    for (dit = fecDown.begin(); dit != fecDown.end();)
    {
        if (dit->peer != peerIP)
        {
            dit++;
            continue;
        }

        EV << "label=" << dit->label << endl;

        // send release message just in case (?)
        // what happens if peer is not really down and
        // hello messages just disappeared?
        // does the protocol recover on its own (XXX check this)

        dit = fecDown.erase(dit);
    }

    EV << "removing bindings from sent to peer=" << peerIP << " from fecUp" << endl;

    FecBindVector::iterator uit;
    for (uit = fecUp.begin(); uit != fecUp.end();)
    {
        if (uit->peer != peerIP)
        {
            uit++;
            continue;
        }

        EV << "label=" << uit->label << endl;

        // send withdraw message just in case (?)
        // see comment above...

        uit = fecUp.erase(uit);
    }

    EV << "updating fecList" << endl;

    updateFecList(peerIP);

    // update TED and routing table

    unsigned int index = tedmod->linkIndex(rt->getRouterId(), peerIP);
    tedmod->ted[index].state = false;
    announceLinkChange(index);
    tedmod->rebuildRoutingTable();
}
void LDP::processLABEL_MAPPING ( LDPLabelMapping *  packet) [protected, virtual]

Referenced by processLDPPacketFromTCP().

{
    FEC_TLV fec = packet->getFec();
    int label = packet->getLabel();
    IPAddress fromIP = packet->getSenderAddress();

    EV << "Label mapping label=" << label << " received for fec=" << fec << " from " << fromIP << endl;

    ASSERT(label > 0);

    FecVector::iterator it = findFecEntry(fecList, fec.addr, fec.length);
    ASSERT(it != fecList.end());

    FecBindVector::iterator dit = findFecEntry(fecDown, it->fecid, fromIP);
    ASSERT(dit == fecDown.end());

    // insert among received mappings

    fec_bind_t newItem;
    newItem.fecid = it->fecid;
    newItem.peer = fromIP;
    newItem.label = label;
    fecDown.push_back(newItem);

    // respond to pending requests

    PendingVector::iterator pit;
    for (pit = pending.begin(); pit != pending.end();)
    {
        if (pit->fecid != it->fecid)
        {
            pit++;
            continue;
        }

        EV << "there's pending request for this FEC from " << pit->peer << ", sending mapping" << endl;

        std::string inInterface = findInterfaceFromPeerAddr(pit->peer);
        std::string outInterface = findInterfaceFromPeerAddr(fromIP);
        LabelOpVector outLabel = LIBTable::swapLabel(label);

        fec_bind_t newItem;
        newItem.fecid = it->fecid;
        newItem.peer = pit->peer;
        newItem.label = lt->installLibEntry(-1, inInterface, outLabel, outInterface, LDP_USER_TRAFFIC);
        fecUp.push_back(newItem);

        EV << "installed LIB entry inLabel=" << newItem.label << " inInterface=" << inInterface <<
                " outLabel=" << outLabel << " outInterface=" << outInterface << endl;

        sendMapping(LABEL_MAPPING, pit->peer, newItem.label, it->addr, it->length);

        // remove request from the list
        pit = pending.erase(pit);
    }

    delete packet;
}
void LDP::processLABEL_RELEASE ( LDPLabelMapping *  packet) [protected, virtual]

Referenced by processLDPPacketFromTCP().

{
    FEC_TLV fec = packet->getFec();
    int label = packet->getLabel();
    IPAddress fromIP = packet->getSenderAddress();

    EV << "Mapping release received for label=" << label << " fec=" << fec << " from " << fromIP << endl;

    ASSERT(label > 0);

    // remove label from fecUp

    FecVector::iterator it = findFecEntry(fecList, fec.addr, fec.length);
    if (it == fecList.end())
    {
        EV << "FEC no longer recognized here, ignoring" << endl;
        delete packet;
        return;
    }

    FecBindVector::iterator uit = findFecEntry(fecUp, it->fecid, fromIP);
    if (uit == fecUp.end() || label != uit->label)
    {
        // this is ok and may happen; e.g. we removed the mapping because downstream
        // neighbour withdrew its mapping. we sent withdraw upstream as well and
        // this is upstream's response
        EV << "mapping not found among sent mappings, ignoring" << endl;
        delete packet;
        return;
    }

    EV << "removing from LIB table label=" << uit->label << endl;
    lt->removeLibEntry(uit->label);

    EV << "removing label from list of sent mappings" << endl;
    fecUp.erase(uit);

    delete packet;
}
void LDP::processLABEL_REQUEST ( LDPLabelRequest *  packet) [protected, virtual]

Referenced by processLDPPacketFromTCP().

{
    FEC_TLV fec = packet->getFec();
    IPAddress srcAddr = packet->getSenderAddress();

    EV << "Label Request from LSR " << srcAddr << " for FEC " << fec << endl;

    FecVector::iterator it = findFecEntry(fecList, fec.addr, fec.length);
    if (it == fecList.end())
    {
        EV << "FEC not recognized, sending back No route message" << endl;

        sendNotify(NO_ROUTE, srcAddr, fec.addr, fec.length);

        delete packet;
        return;
    }

    // do we already have mapping for this fec from our downstream peer?

    //
    // XXX this code duplicates rebuildFecList
    //

    // does upstream have mapping from us?
    FecBindVector::iterator uit = findFecEntry(fecUp, it->fecid, srcAddr);

    // shouldn't!
    ASSERT(uit == fecUp.end());

    // do we have mapping from downstream?
    FecBindVector::iterator dit = findFecEntry(fecDown, it->fecid, it->nextHop);

    // is next hop our LDP peer?
    bool ER = !findPeerSocket(it->nextHop);

    ASSERT(!(ER && dit != fecDown.end())); // can't be egress and have mapping at the same time

    if (ER || dit != fecDown.end())
    {
        fec_bind_t newItem;
        newItem.fecid = it->fecid;
        newItem.label = -1;
        newItem.peer = srcAddr;
        fecUp.push_back(newItem);
        uit = fecUp.end() - 1;
    }

    std::string inInterface = findInterfaceFromPeerAddr(srcAddr);
    std::string outInterface = findInterfaceFromPeerAddr(it->nextHop);

    if (ER)
    {
        // we are egress, that's easy:
        LabelOpVector outLabel = LIBTable::popLabel();

        uit->label = lt->installLibEntry(uit->label, inInterface, outLabel, outInterface, 0);

        EV << "installed (egress) LIB entry inLabel=" << uit->label << " inInterface=" << inInterface <<
                " outLabel=" << outLabel << " outInterface=" << outInterface << endl;

        // We are egress, let our upstream peer know
        // about it by sending back a Label Mapping message

        sendMapping(LABEL_MAPPING, srcAddr, uit->label, fec.addr, fec.length);

    }
    else if (dit != fecDown.end())
    {
        // we have mapping from DS, that's easy
        LabelOpVector outLabel = LIBTable::swapLabel(dit->label);
        uit->label = lt->installLibEntry(uit->label, inInterface, outLabel, outInterface, LDP_USER_TRAFFIC);

        EV << "installed LIB entry inLabel=" << uit->label << " inInterface=" << inInterface <<
                " outLabel=" << outLabel << " outInterface=" << outInterface << endl;

        // We already have a mapping for this FEC, let our upstream peer know
        // about it by sending back a Label Mapping message

        sendMapping(LABEL_MAPPING, srcAddr, uit->label, fec.addr, fec.length);
    }
    else
    {
        // no mapping from DS, mark as pending

        EV << "no mapping for this FEC from the downstream router, marking as pending" << endl;

        pending_req_t newItem;
        newItem.fecid = it->fecid;
        newItem.peer = srcAddr;
        pending.push_back(newItem);
    }

    delete packet;
}
void LDP::processLABEL_WITHDRAW ( LDPLabelMapping *  packet) [protected, virtual]

Referenced by processLDPPacketFromTCP().

{
    FEC_TLV fec = packet->getFec();
    int label = packet->getLabel();
    IPAddress fromIP = packet->getSenderAddress();

    EV << "Mapping withdraw received for label=" << label << " fec=" << fec << " from " << fromIP << endl;

    ASSERT(label > 0);

    // remove label from fecDown

    FecVector::iterator it = findFecEntry(fecList, fec.addr, fec.length);
    if (it == fecList.end())
    {
        EV << "matching FEC not found, ignoring withdraw message" << endl;
        delete packet;
        return;
    }

    FecBindVector::iterator dit = findFecEntry(fecDown, it->fecid, fromIP);

    if (dit == fecDown.end() || label != dit->label)
    {
        EV << "matching mapping not found, ignoring withdraw message" << endl;
        delete packet;
        return;
    }

    ASSERT(dit != fecDown.end());
    ASSERT(label == dit->label);

    EV << "removing label from list of received mappings" << endl;
    fecDown.erase(dit);

    EV << "sending back relase message" << endl;
    packet->setType(LABEL_RELEASE);

    // send msg to peer over TCP
    sendToPeer(fromIP, packet);

    updateFecListEntry(*it);
}
void LDP::processLDPHello ( LDPHello *  msg) [protected, virtual]

Referenced by handleMessage().

{
    UDPControlInfo *controlInfo = check_and_cast<UDPControlInfo *>(msg->getControlInfo());
    //IPAddress peerAddr = controlInfo->getSrcAddr().get4();
    IPAddress peerAddr = msg->getSenderAddress();
    int interfaceId = controlInfo->getInterfaceId();
    delete msg;

    EV << "Received LDP Hello from " << peerAddr << ", ";

    if (peerAddr.isUnspecified() || peerAddr==rt->getRouterId())
    {
        // must be ourselves (we're also in the all-routers multicast group), ignore
        EV << "that's myself, ignore\n";
        return;
    }

    // mark link as working if it was failed, and rebuild table
    unsigned int index = tedmod->linkIndex(rt->getRouterId(), peerAddr);
    if (!tedmod->ted[index].state)
    {
        tedmod->ted[index].state = true;
        tedmod->rebuildRoutingTable();
        announceLinkChange(index);
    }

    // peer already in table?
    int i = findPeer(peerAddr);
    if (i!=-1)
    {
        EV << "already in my peer table, rescheduling timeout" << endl;
        ASSERT(myPeers[i].timeout);
        cancelEvent(myPeers[i].timeout);
        scheduleAt(simTime() + holdTime, myPeers[i].timeout);
        return;
    }

    // not in table, add it
    peer_info info;
    info.peerIP = peerAddr;
    info.linkInterface = ift->getInterfaceById(interfaceId)->getName();
    info.activeRole = peerAddr.getInt() > rt->getRouterId().getInt();
    info.socket = NULL;
    info.timeout = new cMessage("HelloTimeout");
    scheduleAt(simTime() + holdTime, info.timeout);
    myPeers.push_back(info);
    int peerIndex = myPeers.size()-1;

    EV << "added to peer table\n";
    EV << "We'll be " << (info.activeRole ? "ACTIVE" : "PASSIVE") << " in this session\n";

    // introduce ourselves with a Hello, then connect if we're in ACTIVE role
    sendHelloTo(peerAddr);
    if (info.activeRole)
    {
        EV << "Establishing session with it\n";
        openTCPConnectionToPeer(peerIndex);
    }
}
void LDP::processLDPPacketFromTCP ( LDPPacket *  ldpPacket) [protected, virtual]

Referenced by socketDataArrived().

{
    switch (ldpPacket->getType())
    {
    case HELLO:
        error("Received LDP HELLO over TCP (should arrive over UDP)");

    case ADDRESS:
        // processADDRESS(ldpPacket);
        error("Received LDP ADDRESS message, unsupported in this version");
        break;

    case ADDRESS_WITHDRAW:
        // processADDRESS_WITHDRAW(ldpPacket);
        error("LDP PROC DEBUG: Received LDP ADDRESS_WITHDRAW message, unsupported in this version");
        break;

    case LABEL_MAPPING:
        processLABEL_MAPPING(check_and_cast<LDPLabelMapping *>(ldpPacket));
        break;

    case LABEL_REQUEST:
        processLABEL_REQUEST(check_and_cast<LDPLabelRequest *>(ldpPacket));
        break;

    case LABEL_WITHDRAW:
        processLABEL_WITHDRAW(check_and_cast<LDPLabelMapping *>(ldpPacket));
        break;

    case LABEL_RELEASE:
        processLABEL_RELEASE(check_and_cast<LDPLabelMapping *>(ldpPacket));
        break;

    case NOTIFICATION:
        processNOTIFICATION(check_and_cast<LDPNotify*>(ldpPacket));
        break;

    default:
        error("LDP PROC DEBUG: Unrecognized LDP Message Type, type is %d", ldpPacket->getType());
    }
}
void LDP::processMessageFromTCP ( cMessage *  msg) [protected, virtual]

Referenced by handleMessage().

{
    TCPSocket *socket = socketMap.findSocketFor(msg);
    if (!socket)
    {
        // not yet in socketMap, must be new incoming connection.
        // find which peer it is and register connection
        socket = new TCPSocket(msg);
        socket->setOutputGate(gate("tcpOut"));

        // FIXME there seems to be some confusion here. Is it sure that
        // routerIds we use as peerAddrs are the same as IP addresses
        // the routing is based on? --Andras
        IPAddress peerAddr = socket->getRemoteAddress().get4();

        int i = findPeer(peerAddr);
        if (i==-1 || myPeers[i].socket)
        {
            // nothing known about this guy, or already connected: refuse
            socket->close(); // reset()?
            delete socket;
            delete msg;
            return;
        }
        myPeers[i].socket = socket;
        socket->setCallbackObject(this, (void *)i);
        socketMap.addSocket(socket);
    }

    // dispatch to socketEstablished(), socketDataArrived(), socketPeerClosed()
    // or socketFailure()
    socket->processMessage(msg);
}
void LDP::processNOTIFICATION ( LDPNotify *  packet) [protected, virtual]

Referenced by handleMessage(), and processLDPPacketFromTCP().

{
    FEC_TLV fec = packet->getFec();
    IPAddress srcAddr = packet->getSenderAddress();
    int status = packet->getStatus();

    // XXX FIXME NO_ROUTE processing should probably be split into two functions,
    // this is not the cleanest thing I ever wrote :)   --Vojta

    if (packet->isSelfMessage())
    {
        // re-scheduled by ourselves
        EV << "notification retry for peer=" << srcAddr << " fec=" << fec << " status=" << status << endl;
    }
    else
    {
        // received via network
        EV << "notification received from=" << srcAddr << " fec=" << fec << " status=" << status << endl;
    }

    switch(status)
    {
        case NO_ROUTE:
        {
            EV << "route does not exit on that peer" << endl;

            FecVector::iterator it = findFecEntry(fecList, fec.addr, fec.length);
            if (it != fecList.end())
            {
                if (it->nextHop == srcAddr)
                {
                    if (!packet->isSelfMessage())
                    {
                        EV << "we are still interesed in this mapping, we will retry later" << endl;

                        scheduleAt(simTime() + 1.0 /* XXX FIXME */, packet);
                        return;
                    }
                    else
                    {
                        EV << "reissuing request" << endl;

                        sendMappingRequest(srcAddr, fec.addr, fec.length);
                    }
                }
                else
                    EV << "and we still recognize this FEC, but we use different next hop, forget it" << endl;
            }
            else
                EV << "and we do not recognize this any longer, forget it" << endl;

            break;
        }

        default:
            ASSERT(false);
    }

    delete packet;
}
void LDP::rebuildFecList ( ) [protected, virtual]

Referenced by initialize(), and receiveChangeNotification().

{
    EV << "make list of recognized FECs" << endl;

    FecVector oldList = fecList;
    fecList.clear();

    for (int i = 0; i < rt->getNumRoutes(); i++)
    {
        // every entry in the routing table

        const IPRoute *re = rt->getRoute(i);

        // ignore multicast routes
        if (re->getHost().isMulticast())
            continue;

        // find out current next hop according to routing table
        IPAddress nextHop = (re->getType() == IPRoute::DIRECT) ? re->getHost() : re->getGateway();
        ASSERT(!nextHop.isUnspecified());

        EV << "nextHop <-- " << nextHop << endl;

        FecVector::iterator it = findFecEntry(oldList, re->getHost(), re->getNetmask().getNetmaskLength());

        if (it == oldList.end())
        {
            // fec didn't exist, it was just created
            fec_t newItem;
            newItem.fecid = ++maxFecid;
            newItem.addr = re->getHost();
            newItem.length = re->getNetmask().getNetmaskLength();
            newItem.nextHop = nextHop;
            updateFecListEntry(newItem);
            fecList.push_back(newItem);
        }
        else if (it->nextHop != nextHop)
        {
            // next hop for this FEC changed,
            it->nextHop = nextHop;
            updateFecListEntry(*it);
            fecList.push_back(*it);
            oldList.erase(it);
        }
        else
        {
            // FEC didn't change, reusing old values
            fecList.push_back(*it);
            oldList.erase(it);
            continue;
        }
    }


    // our own addresses (XXX is it needed?)

    for (int i = 0; i< ift->getNumInterfaces(); ++i)
    {
        InterfaceEntry *ie = ift->getInterface(i);
        if (ie->getNetworkLayerGateIndex() < 0)
            continue;

        FecVector::iterator it = findFecEntry(oldList, ie->ipv4Data()->getIPAddress(), 32);
        if (it == oldList.end())
        {
            fec_t newItem;
            newItem.fecid = ++maxFecid;
            newItem.addr = ie->ipv4Data()->getIPAddress();
            newItem.length = 32;
            newItem.nextHop = ie->ipv4Data()->getIPAddress();
            fecList.push_back(newItem);
        }
        else
        {
            fecList.push_back(*it);
            oldList.erase(it);
        }
    }

    if (oldList.size() > 0)
    {
        EV << "there are " << oldList.size() << " deprecated FECs, removing them" << endl;

        FecVector::iterator it;
        for (it = oldList.begin(); it != oldList.end(); it++)
        {
            EV << "removing FEC= " << *it << endl;

            FecBindVector::iterator dit;
            for (dit = fecDown.begin(); dit != fecDown.end(); dit++)
            {
                if (dit->fecid != it->fecid)
                    continue;

                EV << "sending release label=" << dit->label << " downstream to " << dit->peer << endl;

                sendMapping(LABEL_RELEASE, dit->peer, dit->label, it->addr, it->length);
            }

            FecBindVector::iterator uit;
            for (uit = fecUp.begin(); uit != fecUp.end(); uit++)
            {
                if (uit->fecid != it->fecid)
                    continue;

                EV << "sending withdraw label=" << uit->label << " upstream to " << uit->peer << endl;

                sendMapping(LABEL_WITHDRAW, uit->peer, uit->label, it->addr, it->length);

                EV << "removing entry inLabel=" << uit->label << " from LIB" << endl;

                lt->removeLibEntry(uit->label);
            }

        }
    }

    // we must keep this list sorted for matching to work correctly
    // this is probably slower than it must be
    std::sort(fecList.begin(), fecList.end(), fecPrefixCompare);
}
void LDP::receiveChangeNotification ( int  category,
const cPolymorphic *  details 
) [protected, virtual]

Called by the NotificationBoard whenever a change of a category occurs to which this client has subscribed.

Implements INotifiable.

{
    Enter_Method_Silent();
    printNotificationBanner(category, details);

    ASSERT(category==NF_IPv4_ROUTE_ADDED || category==NF_IPv4_ROUTE_DELETED);

    EV << "routing table changed, rebuild list of known FEC" << endl;

    rebuildFecList();
}
void LDP::sendHelloTo ( IPAddress  dest) [protected, virtual]

Referenced by handleMessage(), and processLDPHello().

{
    LDPHello *hello = new LDPHello("LDP-Hello");
    hello->setByteLength(LDP_HEADER_BYTES);
    hello->setType(HELLO);
    hello->setSenderAddress(rt->getRouterId());
    //hello->setReceiverAddress(...);
    hello->setHoldTime(SIMTIME_DBL(holdTime));
    //hello->setRbit(...);
    //hello->setTbit(...);
    hello->addPar("color") = LDP_HELLO_TRAFFIC;

    udpSocket.sendTo(hello, dest, LDP_PORT);
}
void LDP::sendMapping ( int  type,
IPAddress  dest,
int  label,
IPAddress  addr,
int  length 
) [protected, virtual]

Referenced by processLABEL_MAPPING(), processLABEL_REQUEST(), rebuildFecList(), and updateFecListEntry().

{
    // Send LABEL MAPPING downstream
    LDPLabelMapping *lmMessage = new LDPLabelMapping("Lb-Mapping");
    lmMessage->setByteLength(LDP_HEADER_BYTES); // FIXME find out actual length
    lmMessage->setType(type);
    lmMessage->setReceiverAddress(dest);
    lmMessage->setSenderAddress(rt->getRouterId());
    lmMessage->setLabel(label);

    FEC_TLV fec;
    fec.addr = addr;
    fec.length = length;

    lmMessage->setFec(fec);

    sendToPeer(dest, lmMessage);
}
void LDP::sendMappingRequest ( IPAddress  dest,
IPAddress  addr,
int  length 
) [protected, virtual]

Referenced by processNOTIFICATION(), and updateFecListEntry().

{
    LDPLabelRequest *requestMsg = new LDPLabelRequest("Lb-Req");
    requestMsg->setByteLength(LDP_HEADER_BYTES); // FIXME find out actual length
    requestMsg->setType(LABEL_REQUEST);

    FEC_TLV fec;
    fec.addr = addr;
    fec.length = length;
    requestMsg->setFec(fec);

    requestMsg->setReceiverAddress(dest);
    requestMsg->setSenderAddress(rt->getRouterId());

    sendToPeer(dest, requestMsg);
}
void LDP::sendNotify ( int  status,
IPAddress  dest,
IPAddress  addr,
int  length 
) [protected, virtual]

Referenced by processLABEL_REQUEST().

{
    // Send NOTIFY message
    LDPNotify *lnMessage = new LDPNotify("Lb-Notify");
    lnMessage->setByteLength(LDP_HEADER_BYTES); // FIXME find out actual length
    lnMessage->setType(NOTIFICATION);
    lnMessage->setStatus(NO_ROUTE);
    lnMessage->setReceiverAddress(dest);
    lnMessage->setSenderAddress(rt->getRouterId());

    FEC_TLV fec;
    fec.addr = addr;
    fec.length = length;

    lnMessage->setFec(fec);

    sendToPeer(dest, lnMessage);
}
void LDP::sendToPeer ( IPAddress  dest,
cMessage *  msg 
) [protected, virtual]
void LDP::socketClosed ( int  connId,
void *  yourPtr 
) [protected, virtual]

Reimplemented from TCPSocket::CallbackInterface.

{
    peer_info& peer = myPeers[(long)yourPtr];
    EV << "TCP connection to peer " << peer.peerIP << " closed\n";

    ASSERT(false);

    // FIXME what now? reconnect after a delay?
}
void LDP::socketDataArrived ( int  connId,
void *  yourPtr,
cPacket *  msg,
bool  urgent 
) [protected, virtual]

Implements TCPSocket::CallbackInterface.

{
    peer_info& peer = myPeers[(long)yourPtr];
    EV << "Message arrived over TCP from peer " << peer.peerIP << "\n";

    delete msg->removeControlInfo();
    processLDPPacketFromTCP(check_and_cast<LDPPacket *>(msg));
}
void LDP::socketEstablished ( int  connId,
void *  yourPtr 
) [protected, virtual]

Reimplemented from TCPSocket::CallbackInterface.

{
    peer_info& peer = myPeers[(long)yourPtr];
    EV << "TCP connection established with peer " << peer.peerIP << "\n";

    // we must update all entries with nextHop == peerIP
    updateFecList(peer.peerIP);

    // FIXME start LDP session setup (if we're on the active side?)
}
void LDP::socketFailure ( int  connId,
void *  yourPtr,
int  code 
) [protected, virtual]

Reimplemented from TCPSocket::CallbackInterface.

{
    peer_info& peer = myPeers[(long)yourPtr];
    EV << "TCP connection to peer " << peer.peerIP << " broken\n";

    ASSERT(false);

    // FIXME what now? reconnect after a delay?
}
void LDP::socketPeerClosed ( int  connId,
void *  yourPtr 
) [protected, virtual]

Reimplemented from TCPSocket::CallbackInterface.

{
    peer_info& peer = myPeers[(long)yourPtr];
    EV << "Peer " << peer.peerIP << " closed TCP connection\n";

    ASSERT(false);

/*
    // close the connection (if not already closed)
    if (socket.getState()==TCPSocket::PEER_CLOSED)
    {
        EV << "remote TCP closed, closing here as well\n";
        close();
    }
*/
}
virtual void LDP::socketStatusArrived ( int  connId,
void *  yourPtr,
TCPStatusInfo *  status 
) [inline, protected, virtual]

Reimplemented from TCPSocket::CallbackInterface.

{delete status;}
void LDP::updateFecList ( IPAddress  nextHop) [protected, virtual]

Referenced by processHelloTimeout(), and socketEstablished().

{
    FecVector::iterator it;
    for (it = fecList.begin(); it != fecList.end(); it++)
    {
        if (it->nextHop != nextHop)
            continue;

        updateFecListEntry(*it);
    }
}
void LDP::updateFecListEntry ( LDP::fec_t  oldItem) [protected, virtual]

Referenced by processLABEL_WITHDRAW(), rebuildFecList(), and updateFecList().

{
    // do we have mapping from downstream?
    FecBindVector::iterator dit = findFecEntry(fecDown, oldItem.fecid, oldItem.nextHop);

    // is next hop our LDP peer?
    bool ER = findPeerSocket(oldItem.nextHop)==NULL;

    ASSERT(!(ER && dit != fecDown.end())); // can't be egress and have mapping at the same time

    // adjust upstream mappings
    FecBindVector::iterator uit;
    for (uit = fecUp.begin(); uit != fecUp.end();)
    {
        if (uit->fecid != oldItem.fecid)
        {
            uit++;
            continue;
        }

        std::string inInterface = findInterfaceFromPeerAddr(uit->peer);
        std::string outInterface = findInterfaceFromPeerAddr(oldItem.nextHop);
        if (ER)
        {
            // we are egress, that's easy:
            LabelOpVector outLabel = LIBTable::popLabel();
            uit->label = lt->installLibEntry(uit->label, inInterface, outLabel, outInterface, LDP_USER_TRAFFIC);

            EV << "installed (egress) LIB entry inLabel=" << uit->label << " inInterface=" << inInterface <<
                    " outLabel=" << outLabel << " outInterface=" << outInterface << endl;
            uit++;
        }
        else if (dit != fecDown.end())
        {
            // we have mapping from DS, that's easy
            LabelOpVector outLabel = LIBTable::swapLabel(dit->label);
            uit->label = lt->installLibEntry(uit->label, inInterface, outLabel, outInterface, LDP_USER_TRAFFIC);

            EV << "installed LIB entry inLabel=" << uit->label << " inInterface=" << inInterface <<
                    " outLabel=" << outLabel << " outInterface=" << outInterface << endl;
            uit++;
        }
        else
        {
            // no mapping from DS, withdraw mapping US
            EV << "sending withdraw message upstream" << endl;
            sendMapping(LABEL_WITHDRAW, uit->peer, uit->label, oldItem.addr, oldItem.length);

            // remove from US mappings
            uit = fecUp.erase(uit);
        }
    }

    if (!ER && dit == fecDown.end())
    {
        // and ask DS for mapping
        EV << "sending request message downstream" << endl;
        sendMappingRequest(oldItem.nextHop, oldItem.addr, oldItem.length);
    }
}

Member Data Documentation

simtime_t LDP::helloInterval [protected]

Referenced by handleMessage(), and initialize().

simtime_t LDP::holdTime [protected]
int LDP::maxFecid [protected]

Referenced by initialize(), and rebuildFecList().

NotificationBoard* LDP::nb [protected]

Referenced by announceLinkChange(), and initialize().

cMessage* LDP::sendHelloMsg [protected]

Referenced by handleMessage(), initialize(), LDP(), and ~LDP().

Referenced by initialize().

Referenced by initialize(), and sendHelloTo().


The documentation for this class was generated from the following files: