diff --git a/examples/bgpv4/BgpLifecycle/BGPConfig.xml b/examples/bgpv4/BgpLifecycle/BGPConfig.xml new file mode 100644 index 00000000000..92f6331a1ed --- /dev/null +++ b/examples/bgpv4/BgpLifecycle/BGPConfig.xml @@ -0,0 +1,27 @@ + + + + + 120 + 180 + 60 + 2 + + + + + + + + + + + + + + + + + + + diff --git a/examples/bgpv4/BgpLifecycle/IPv4Config.xml b/examples/bgpv4/BgpLifecycle/IPv4Config.xml new file mode 100644 index 00000000000..9ec7919a1af --- /dev/null +++ b/examples/bgpv4/BgpLifecycle/IPv4Config.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/examples/bgpv4/BgpLifecycle/Network.ned b/examples/bgpv4/BgpLifecycle/Network.ned new file mode 100644 index 00000000000..f849685abe8 --- /dev/null +++ b/examples/bgpv4/BgpLifecycle/Network.ned @@ -0,0 +1,70 @@ +package inet.examples.bgpv4.BgpLifecycle; + +import inet.common.misc.ThruputMeteringChannel; +import inet.common.scenario.ScenarioManager; +import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator; +import inet.node.bgp.BgpRouter; +import inet.node.inet.StandardHost; +import inet.visualizer.canvas.integrated.IntegratedCanvasVisualizer; + +network BgpNetwork +{ + types: + channel LINK_100 extends ThruputMeteringChannel + { + parameters: + delay = 50us; + datarate = 100Mbps; + displayAsTooltip = true; + thruputDisplayFormat = "#N"; + } + submodules: + visualizer: IntegratedCanvasVisualizer { + parameters: + @display("p=100,100;is=s"); + } + configurator: Ipv4NetworkConfigurator { + parameters: + @display("p=100,200;is=s"); + config = xmldoc("IPv4Config.xml"); + addStaticRoutes = false; + addDefaultRoutes = false; + addSubnetRoutes = false; + } + scenarioManager: ScenarioManager { + parameters: + @display("p=100,300;is=s"); + } + A: BgpRouter { + parameters: + hasStatus = true; + @display("p=400,100"); + gates: + pppg[1]; + ethg[1]; + } + B: BgpRouter { + parameters: + hasStatus = true; + @display("p=550,100"); + gates: + pppg[1]; + ethg[1]; + } + H1: StandardHost { + parameters: + @display("p=250,100;i=device/laptop"); + gates: + ethg[1]; + } + H2: StandardHost { + parameters: + @display("p=700,100;i=device/laptop"); + gates: + ethg[1]; + } + connections: + H1.ethg[0] <--> LINK_100 <--> A.ethg[0]; + A.pppg[0] <--> LINK_100 <--> B.pppg[0]; + B.ethg[0] <--> LINK_100 <--> H2.ethg[0]; +} diff --git a/examples/bgpv4/BgpLifecycle/OSPFConfig.xml b/examples/bgpv4/BgpLifecycle/OSPFConfig.xml new file mode 100644 index 00000000000..cf898770919 --- /dev/null +++ b/examples/bgpv4/BgpLifecycle/OSPFConfig.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/bgpv4/BgpLifecycle/network.jpg b/examples/bgpv4/BgpLifecycle/network.jpg new file mode 100644 index 00000000000..54518d865cf Binary files /dev/null and b/examples/bgpv4/BgpLifecycle/network.jpg differ diff --git a/examples/bgpv4/BgpLifecycle/omnetpp.ini b/examples/bgpv4/BgpLifecycle/omnetpp.ini new file mode 100644 index 00000000000..71f51353ff7 --- /dev/null +++ b/examples/bgpv4/BgpLifecycle/omnetpp.ini @@ -0,0 +1,53 @@ +[General] +description = "BGP lifecycle operations" +network = BgpNetwork +sim-time-limit = 900s +output-scalar-file = results.sca +output-scalar-precision = 5 + +**.app[0].**.scalar-recording = true +**.bgp.**.scalar-recording = true +**.scalar-recording = false +**.vector-recording = false + +# NIC configuration +**.eth[*].queue.packetCapacity = 100 + +#tcp settings +**.tcp.typename = "Tcp" +**.tcp.mss = 1024 +**.tcp.advertisedWindow = 14336 +**.tcp.tcpAlgorithmClass = "TcpReno" + +# OSPF configuration +**.ospfConfig = xmldoc("OSPFConfig.xml") + +# bgp settings +**.bgpConfig = xmldoc("BGPConfig.xml") +**.redistributeOspf = "O IA" + +# Visualizer settings +*.visualizer.interfaceTableVisualizer.displayInterfaceTables = true + +# UDPApp parameters +*.H*.numApps = 1 +**.app[0].messageLength = 32 bytes +**.app[0].sendInterval = 10s +**.app[0].startTime = 80s +**.app[0].destPort = 5678 + +**.H1.app[0].typename = "UdpBasicApp" +**.H1.app[0].localPort = 1234 +**.H1.app[0].destAddresses = "192.168.2.1" + +**.H2.app[0].typename="UdpSink" +**.H2.app[0].localPort = 5678 + +# Lifecycle operations: allow BGP sessions to establish, stop router A +# gracefully, restart it, then crash it later in the run. +*.scenarioManager.script = xml( \ + "") diff --git a/src/inet/routing/bgpv4/Bgp.cc b/src/inet/routing/bgpv4/Bgp.cc index 528ba51e731..3ddba9206d3 100644 --- a/src/inet/routing/bgpv4/Bgp.cc +++ b/src/inet/routing/bgpv4/Bgp.cc @@ -7,7 +7,6 @@ #include "inet/routing/bgpv4/Bgp.h" #include "inet/common/ModuleAccess.h" -#include "inet/common/lifecycle/NodeStatus.h" #include "inet/routing/bgpv4/BgpConfigReader.h" #include "inet/routing/bgpv4/BgpSession.h" @@ -28,33 +27,19 @@ Bgp::~Bgp() void Bgp::initialize(int stage) { - SimpleModule::initialize(stage); + RoutingProtocolBase::initialize(stage); if (stage == INITSTAGE_LOCAL) { ift.reference(this, "interfaceTableModule", true); rt.reference(this, "routingTableModule", true); startupTimer = new cMessage("BGP-startup"); - - WATCH(isUp); - } - else if (stage == INITSTAGE_ROUTING_PROTOCOLS) { // interfaces and static routes are already initialized - cModule *node = findContainingNode(this); - NodeStatus *nodeStatus = node ? check_and_cast_nullable(node->getSubmodule("status")) : nullptr; - isUp = !nodeStatus || nodeStatus->getState() == NodeStatus::UP; - if (isUp) { - simtime_t startupTime = par("startupTime"); - if (startupTime == 0) - createBgpRouter(); - else - scheduleAfter(startupTime, startupTimer); - } } } void Bgp::finish() { - if (!isUp) { + if (!bgpRouter) { EV_ERROR << "Protocol is turned off. \n"; return; } @@ -62,28 +47,75 @@ void Bgp::finish() bgpRouter->recordStatistics(); } -void Bgp::handleMessage(cMessage *msg) +void Bgp::handleMessageWhenUp(cMessage *msg) { - if (!isUp) { - if (msg->isSelfMessage()) - throw cRuntimeError("Model error: self msg '%s' received when protocol is down", msg->getName()); - EV_ERROR << "Protocol is turned off, dropping '" << msg->getName() << "' message\n"; - delete msg; - return; + if (msg == startupTimer) + createBgpRouter(); + else { + if (!bgpRouter) { + if (msg->isSelfMessage()) + throw cRuntimeError("Model error: self msg '%s' received before BGP startup", msg->getName()); + EV_WARN << "BGP has not started yet, dropping '" << msg->getName() << "' message\n"; + delete msg; + } + else if (msg->isSelfMessage()) // BGP level + handleTimer(msg); + else if (!strcmp(msg->getArrivalGate()->getName(), "socketIn")) // TCP level + bgpRouter->processMessageFromTCP(msg); + else + delete msg; } +} - if (msg == startupTimer) +void Bgp::handleStartOperation(LifecycleOperation *operation) +{ + startBgp(); +} + +void Bgp::handleStopOperation(LifecycleOperation *operation) +{ + stopBgp(false); +} + +void Bgp::handleCrashOperation(LifecycleOperation *operation) +{ + stopBgp(true); +} + +void Bgp::startBgp() +{ + ASSERT(bgpRouter == nullptr); + simtime_t startupTime = par("startupTime"); + if (startupTime == 0) createBgpRouter(); - else if (msg->isSelfMessage()) // BGP level - handleTimer(msg); - else if (!strcmp(msg->getArrivalGate()->getName(), "socketIn")) // TCP level - bgpRouter->processMessageFromTCP(msg); else - delete msg; + scheduleAfter(startupTime, startupTimer); +} + +void Bgp::stopBgp(bool abort) +{ + cancelEvent(startupTimer); + removeBgpRoutes(); + if (bgpRouter) + bgpRouter->closeSessions(abort); + delete bgpRouter; + bgpRouter = nullptr; +} + +void Bgp::removeBgpRoutes() +{ + for (int i = rt->getNumRoutes() - 1; i >= 0; i--) { + Ipv4Route *route = rt->getRoute(i); + if (route->getSourceType() == IRoute::BGP) { + EV_INFO << "Removing BGP route " << route->str() << endl; + rt->deleteRoute(route); + } + } } void Bgp::createBgpRouter() { + ASSERT(bgpRouter == nullptr); bgpRouter = new BgpRouter(this, ift, rt); // read BGP configuration @@ -128,4 +160,3 @@ void Bgp::handleTimer(cMessage *timer) } // namespace bgp } // namespace inet - diff --git a/src/inet/routing/bgpv4/Bgp.h b/src/inet/routing/bgpv4/Bgp.h index 435d85a7da5..3b960075d51 100644 --- a/src/inet/routing/bgpv4/Bgp.h +++ b/src/inet/routing/bgpv4/Bgp.h @@ -7,10 +7,9 @@ #ifndef __INET_BGP_H #define __INET_BGP_H -#include "inet/common/SimpleModule.h" -#include "inet/common/lifecycle/LifecycleUnsupported.h" #include "inet/networklayer/contract/ipv4/Ipv4Address.h" #include "inet/networklayer/ipv4/Ipv4InterfaceData.h" +#include "inet/routing/base/RoutingProtocolBase.h" #include "inet/routing/bgpv4/BgpCommon.h" #include "inet/routing/bgpv4/BgpRouter.h" #include "inet/routing/bgpv4/bgpmessage/BgpHeader_m.h" @@ -19,12 +18,11 @@ namespace inet { namespace bgp { -class INET_API Bgp : public SimpleModule, protected cListener, public LifecycleUnsupported +class INET_API Bgp : public RoutingProtocolBase, protected cListener { private: ModuleRefByPar rt; ModuleRefByPar ift; - bool isUp = false; BgpRouter *bgpRouter = nullptr; // data structure to fill in cMessage *startupTimer = nullptr; // timer for delayed startup @@ -35,7 +33,13 @@ class INET_API Bgp : public SimpleModule, protected cListener, public LifecycleU protected: virtual int numInitStages() const override { return NUM_INIT_STAGES; } virtual void initialize(int stage) override; - virtual void handleMessage(cMessage *msg) override; + virtual void handleMessageWhenUp(cMessage *msg) override; + virtual void handleStartOperation(LifecycleOperation *operation) override; + virtual void handleStopOperation(LifecycleOperation *operation) override; + virtual void handleCrashOperation(LifecycleOperation *operation) override; + void startBgp(); + void stopBgp(bool abort); + void removeBgpRoutes(); void createBgpRouter(); void handleTimer(cMessage *timer); virtual void finish() override; @@ -46,4 +50,3 @@ class INET_API Bgp : public SimpleModule, protected cListener, public LifecycleU } // namespace inet #endif - diff --git a/src/inet/routing/bgpv4/BgpFsm.cc b/src/inet/routing/bgpv4/BgpFsm.cc index 31701aca05d..d404e6e7215 100644 --- a/src/inet/routing/bgpv4/BgpFsm.cc +++ b/src/inet/routing/bgpv4/BgpFsm.cc @@ -78,6 +78,8 @@ void Connect::HoldTimer_Expires() // - changes its state to Idle. session._info.sessionEstablished = false; setState(); + if (session.isLifecycleNode()) + session.startConnection(); } void Connect::KeepaliveTimer_Expires() @@ -156,6 +158,8 @@ void Active::HoldTimer_Expires() // - changes its state to Idle. session._info.sessionEstablished = false; setState(); + if (session.isLifecycleNode()) + session.startConnection(); } void Active::KeepaliveTimer_Expires() @@ -444,6 +448,8 @@ void Established::ConnectRetryTimer_Expires() // - changes its state to Idle. session._info.sessionEstablished = false; setState(); + if (session.isLifecycleNode()) + session.startConnection(); } void Established::HoldTimer_Expires() @@ -461,6 +467,8 @@ void Established::HoldTimer_Expires() // - changes its state to Idle. session._info.sessionEstablished = false; setState(); + if (session.isLifecycleNode()) + session.startConnection(); } void Established::KeepaliveTimer_Expires() @@ -479,6 +487,14 @@ void Established::KeepaliveTimer_Expires() void Established::TcpConnectionFails() { EV_TRACE << "Processing Established::TcpConnectionFails" << std::endl; + BgpSession& session = TopState::box().getModule(); + session.restartsConnectRetryTimer(false); + session._info.socket->abort(); + ++session._connectRetryCounter; + session._info.sessionEstablished = false; + setState(); + if (session.isLifecycleNode()) + session.startConnection(); } void Established::OpenMsgEvent() diff --git a/src/inet/routing/bgpv4/BgpRouter.cc b/src/inet/routing/bgpv4/BgpRouter.cc index 901441fe9d2..254e7b22aa5 100644 --- a/src/inet/routing/bgpv4/BgpRouter.cc +++ b/src/inet/routing/bgpv4/BgpRouter.cc @@ -78,6 +78,22 @@ void BgpRouter::recordStatistics() bgpModule->recordScalar("UpdateMsgRcv", statTab[5]); } +void BgpRouter::closeSessions(bool abort) +{ + for (auto& elem : _BGPSessions) { + TcpSocket *socket = elem.second->getSocket(); + if (socket) { + _socketMap.removeSocket(socket); + abort ? socket->abort() : socket->close(); + } + TcpSocket *socketListen = elem.second->getSocketListen(); + if (socketListen) { + _socketMap.removeSocket(socketListen); + abort ? socketListen->abort() : socketListen->close(); + } + } +} + SessionId BgpRouter::createIbgpSession(const char *peerAddr) { SessionInfo info; @@ -415,6 +431,15 @@ void BgpRouter::socketFailure(TcpSocket *socket, int code) } } +void BgpRouter::socketPeerClosed(TcpSocket *socket) +{ + socket->close(); + int connId = socket->getSocketId(); + _currSessionId = findIdFromSocketConnId(_BGPSessions, connId); + if (_currSessionId != static_cast(-1)) + _BGPSessions[_currSessionId]->getFSM()->TcpConnectionFails(); +} + void BgpRouter::socketDataArrived(TcpSocket *socket) { auto queue = socket->getReadBuffer(); @@ -1099,4 +1124,3 @@ bool BgpRouter::isReachable(const Ipv4Address addr) const } // namespace bgp } // namespace inet - diff --git a/src/inet/routing/bgpv4/BgpRouter.h b/src/inet/routing/bgpv4/BgpRouter.h index 73776578fb3..48d83a86c49 100644 --- a/src/inet/routing/bgpv4/BgpRouter.h +++ b/src/inet/routing/bgpv4/BgpRouter.h @@ -80,6 +80,7 @@ class INET_API BgpRouter : public TcpSocket::BufferingCallback void printSessionSummary(); void addWatches(); void recordStatistics(); + void closeSessions(bool abort); SessionId createEbgpSession(const char *peerAddr, SessionInfo& externalInfo); SessionId createIbgpSession(const char *peerAddr); @@ -105,7 +106,7 @@ class INET_API BgpRouter : public TcpSocket::BufferingCallback virtual void socketDataArrived(TcpSocket *socket, Packet *packet, bool urgent) override; virtual void socketAvailable(TcpSocket *socket, TcpAvailableInfo *availableInfo) override { socket->accept(availableInfo->getNewSocketId()); } // TODO virtual void socketEstablished(TcpSocket *socket) override; - virtual void socketPeerClosed(TcpSocket *socket) override {} + virtual void socketPeerClosed(TcpSocket *socket) override; virtual void socketClosed(TcpSocket *socket) override {} virtual void socketFailure(TcpSocket *socket, int code) override; virtual void socketStatusArrived(TcpSocket *socket, TcpStatusInfo *status) override {} @@ -119,6 +120,7 @@ class INET_API BgpRouter : public TcpSocket::BufferingCallback cMessage *getCancelEvent(cMessage *msg) { return bgpModule->cancelEvent(msg); } IIpv4RoutingTable *getIPRoutingTable() { return rt; } std::vector getBGPRoutingTable() { return bgpRoutingTable; } + bool isLifecycleNode() const { return bgpModule->getParentModule()->getSubmodule("status") != nullptr; } /** * \brief active listenSocket for a given session (used by fsm) @@ -181,4 +183,3 @@ class INET_API BgpRouter : public TcpSocket::BufferingCallback } // namespace inet #endif - diff --git a/src/inet/routing/bgpv4/BgpSession.cc b/src/inet/routing/bgpv4/BgpSession.cc index c5df42604c0..5f809337394 100644 --- a/src/inet/routing/bgpv4/BgpSession.cc +++ b/src/inet/routing/bgpv4/BgpSession.cc @@ -77,13 +77,11 @@ void BgpSession::startConnection() if (_ptrStartEvent == nullptr) _ptrStartEvent = new cMessage("BGP Start", START_EVENT_KIND); - if (_info.sessionType == IGP) { - if (simTime() > _StartEventTime) - _StartEventTime = simTime(); - if (!_ptrStartEvent->isScheduled()) - bgpRouter.getScheduleAt(_StartEventTime, _ptrStartEvent); - _ptrStartEvent->setContextPointer(this); - } + if (simTime() > _StartEventTime) + _StartEventTime = simTime(); + if (!_ptrStartEvent->isScheduled()) + bgpRouter.getScheduleAt(_StartEventTime, _ptrStartEvent); + _ptrStartEvent->setContextPointer(this); } void BgpSession::restartsHoldTimer() @@ -232,4 +230,3 @@ std::ostream& operator<<(std::ostream& out, const BgpSession& entry) } // namespace bgp } // namespace inet - diff --git a/src/inet/routing/bgpv4/BgpSession.h b/src/inet/routing/bgpv4/BgpSession.h index b85eedda29a..d5a458c6b0a 100644 --- a/src/inet/routing/bgpv4/BgpSession.h +++ b/src/inet/routing/bgpv4/BgpSession.h @@ -101,6 +101,7 @@ class INET_API BgpSession : public cObject static const std::string getTypeString(BgpSessionType sessionType); NetworkInterface *getLinkIntf() const { return _info.linkIntf; } bool getCheckConnection() const { return _info.checkConnection; } + bool isLifecycleNode() const { return bgpRouter.isLifecycleNode(); } Ipv4Address getPeerAddr() const { return _info.peerAddr; } bool getNextHopSelf() const { return _info.nextHopSelf; } int getLocalPreference() const { return _info.localPreference; } @@ -120,4 +121,3 @@ std::ostream& operator<<(std::ostream& out, const BgpSession& entry); } // namespace inet #endif - diff --git a/tests/fingerprint/examples.csv b/tests/fingerprint/examples.csv index 565090dcef5..7de4817851b 100644 --- a/tests/fingerprint/examples.csv +++ b/tests/fingerprint/examples.csv @@ -26,6 +26,7 @@ /examples/bgpv4/Bgp2RoutersInAS/, -f omnetpp.ini -c General -r 0, 1000s, 096d-ba3e/tplx;c504-7297/~tNl;c40f-3bef/~tND;21c2-3739/tyf, PASS, ospf EthernetMac Ipv4 /examples/bgpv4/Bgp3Routers/, -f omnetpp.ini -c General -r 0, 1000s, 0743-0419/tplx;2c93-b913/~tNl;abc7-4ccf/~tND;4ae7-55e4/tyf, PASS, ospf EthernetMac Ipv4 /examples/bgpv4/BgpCompleteTest/, -f omnetpp.ini -c General -r 0, 1000s, 1b55-5b10/tplx;a62e-572b/~tNl;ed1b-2f1f/~tND;06a0-ffe5/tyf, PASS, ospf EthernetMac Ipv4 +/examples/bgpv4/BgpLifecycle/, -f omnetpp.ini -c General -r 0, 900s, 66c3-9aef/tplx;ba07-f473/~tNl;39cb-270d/~tND;443b-48cc/tyf, PASS, ospf EthernetMac Ipv4 lifecycle /examples/bgpv4/BgpOpen/, -f omnetpp.ini -c General -r 0, 62s, f559-6038/tplx;9dce-698e/~tNl;400e-d43e/~tND;0f2b-99dc/tyf, PASS, ospf Ipv4 /examples/bgpv4/BgpUpdate/, -f omnetpp.ini -c General -r 0, 30s, c6af-84d3/tplx;3a06-a4f0/~tNl;3967-7b00/~tND;5cdf-d2f9/tyf, PASS, ospf EthernetMac Ipv4 /examples/bgpv4/BgpAndOspf/, -f omnetpp.ini -c General -r 0, 1000s, 136d-4446/tplx;7a5d-2469/~tNl;263a-e848/~tND;a746-abf9/tyf, PASS, ospf EthernetMac Ipv4