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