From 1c176bb1cc8c2b470558f4ffdb099107eb8974a7 Mon Sep 17 00:00:00 2001 From: paulc Date: Wed, 1 Sep 2010 12:05:55 +0000 Subject: [PATCH] Added support for reporting route congestion. Detection is currently implemented only on SIGTRAN M2UA. git-svn-id: http://yate.null.ro/svn/yate/trunk@3619 acf43c95-373e-0410-b603-e72c3f656dc1 --- libs/ysig/layer3.cpp | 19 ++++++++++++++++ libs/ysig/management.cpp | 3 ++- libs/ysig/router.cpp | 49 ++++++++++++++++++++++++++++++++++++---- libs/ysig/sigtran.cpp | 16 +++++++++++++ libs/ysig/yatesig.h | 43 ++++++++++++++++++++++++++++++++--- 5 files changed, 122 insertions(+), 8 deletions(-) diff --git a/libs/ysig/layer3.cpp b/libs/ysig/layer3.cpp index 4edd2350..9969b104 100644 --- a/libs/ysig/layer3.cpp +++ b/libs/ysig/layer3.cpp @@ -705,6 +705,25 @@ bool SS7MTP3::inhibit(int sls, int setFlags, int clrFlags) return false; } +unsigned int SS7MTP3::congestion(int sls) +{ + unsigned int level = 0; + const ObjList* l = &m_links; + for (; l; l = l->next()) { + L2Pointer* p = static_cast(l->get()); + if (!(p && *p)) + continue; + if ((*p)->sls() == sls) + return (*p)->congestion(); + else if (sls >= 0) { + unsigned int cong = (*p)->congestion();; + if (level < cong) + level = cong; + } + } + return level; +} + int SS7MTP3::getSequence(int sls) const { if (sls < 0) diff --git a/libs/ysig/management.cpp b/libs/ysig/management.cpp index c1a3fadc..a3fecff6 100644 --- a/libs/ysig/management.cpp +++ b/libs/ysig/management.cpp @@ -171,7 +171,7 @@ SS7MsgSNM* SS7MsgSNM::parse(SS7Management* receiver, unsigned char type, do { // TFP,TFR,TFA: Q.704 15.7, RST,RSR: Q.704 15.10 // There must be at least 2 bytes in buffer - if (type == TFP || type == TFR || type == TFA || + if (type == TFP || type == TFR || type == TFA || type == TFC || type == RST || type == RSR) { // 2 bytes destination SS7PointCode pc; @@ -390,6 +390,7 @@ HandledMSU SS7Management::receivedMSU(const SS7MSU& msu, const SS7Label& label, if (msg->type() == SS7MsgSNM::TFP || msg->type() == SS7MsgSNM::TFR || msg->type() == SS7MsgSNM::TFA || + msg->type() == SS7MsgSNM::TFC || msg->type() == SS7MsgSNM::RST || msg->type() == SS7MsgSNM::RSR) { String dest = msg->params().getValue("destination"); diff --git a/libs/ysig/router.cpp b/libs/ysig/router.cpp index 49e16a16..2a3cf0d5 100644 --- a/libs/ysig/router.cpp +++ b/libs/ysig/router.cpp @@ -168,6 +168,17 @@ bool SS7Route::operational(int sls) return false; } +// Check and reset congestion status +bool SS7Route::congested() +{ + if (m_congCount >= 8 || m_congBytes >= 256) { + m_congCount = 0; + m_congBytes = 0; + return true; + } + return false; +} + // Try to transmit a MSU through one of the attached networks int SS7Route::transmitMSU(const SS7Router* router, const SS7MSU& msu, const SS7Label& label, int sls, const SS7Layer3* source) @@ -182,8 +193,14 @@ int SS7Route::transmitMSU(const SS7Router* router, const SS7MSU& msu, XDebug(router,DebugAll,"Attempting transmitMSU on L3=%p '%s' [%p]", (void*)l3,l3->toString().c_str(),router); int res = l3->transmitMSU(msu,label,sls); - if (res != -1) + if (res != -1) { + unsigned int cong = l3->congestion(res); + if (cong) { + m_congCount++; + m_congBytes += msu.length(); + } return res; + } lock(); } unlock(); @@ -200,7 +217,7 @@ SS7Router::SS7Router(const NamedList& params) m_changes(0), m_transfer(false), m_phase2(false), m_started(false), m_restart(0), m_isolate(0), m_routeTest(0), m_testRestricted(false), m_checkRoutes(false), m_sendUnavail(true), m_sendProhibited(true), - m_rxMsu(0), m_txMsu(0), m_fwdMsu(0), + m_rxMsu(0), m_txMsu(0), m_fwdMsu(0), m_congestions(0), m_mngmt(0) { #ifdef DEBUG @@ -223,8 +240,8 @@ SS7Router::SS7Router(const NamedList& params) SS7Router::~SS7Router() { - Debug(this,DebugInfo,"SS7Router destroyed, rx=%lu, tx=%lu, fwd=%lu", - m_rxMsu,m_txMsu,m_fwdMsu); + Debug(this,DebugInfo,"SS7Router destroyed, rx=%lu, tx=%lu, fwd=%lu, cong=%lu", + m_rxMsu,m_txMsu,m_fwdMsu,m_congestions); } bool SS7Router::initialize(const NamedList* config) @@ -538,10 +555,34 @@ int SS7Router::routeMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* net unlock(); int slsTx = route ? route->transmitMSU(this,msu,label,sls,network) : -1; if (slsTx >= 0) { + bool cong = route->congested(); + if (cong) { + Debug(this,DebugMild,"Route to %u reports congestion",route->packed()); + while (m_mngmt) { + unsigned int local = getLocal(label.type()); + if (!local) + break; + NamedList* ctl = m_mngmt->controlCreate("congest"); + if (!ctl) + break; + String addr; + addr << SS7PointCode::lookup(label.type()) << ","; + addr << SS7PointCode(label.type(),local) << "," << label.opc(); + String dest; + dest << SS7PointCode(label.type(),route->packed()); + ctl->addParam("address",addr); + ctl->addParam("destination",dest); + ctl->setParam("automatic",String::boolText(true)); + m_mngmt->controlExecute(ctl); + break; + } + } lock(); m_txMsu++; if (network) m_fwdMsu++; + if (cong) + m_congestions++; unlock(); } return slsTx; diff --git a/libs/ysig/sigtran.cpp b/libs/ysig/sigtran.cpp index 6a4ffed7..4e4ff8fa 100644 --- a/libs/ysig/sigtran.cpp +++ b/libs/ysig/sigtran.cpp @@ -1669,6 +1669,7 @@ bool SS7M2UA::processMAUP(unsigned char msgType, const DataBlock& msg, int strea case 3: // Establish Confirm m_lastSeqRx = -1; m_linkState = LinkUp; + m_congestion = 0; m_rpo = false; SS7Layer2::notify(); return true; @@ -1751,6 +1752,20 @@ bool SS7M2UA::processMAUP(unsigned char msgType, const DataBlock& msg, int strea return recoveredMSU(data); } break; + case 14: // Congestion Indication + { + u_int32_t cong = 0; + if (!SIGAdaptation::getTag(msg,0x0304,cong)) { + err = "Missing congestion state"; + break; + } + u_int32_t disc = 0; + SIGAdaptation::getTag(msg,0x0305,disc); + int level = disc ? DebugWarn : (cong ? DebugMild : DebugNote); + Debug(this,level,"Congestion level %u, discard level %u",cong,disc); + m_congestion = cong; + } + return true; } Debug(this,DebugStub,"%s M2UA MAUP message type %u",err,msgType); return false; @@ -1760,6 +1775,7 @@ void SS7M2UA::activeChange(bool active) { if (!active) { getSequence(); + m_congestion = 0; m_rpo = false; switch (m_linkState) { case LinkUpEmg: diff --git a/libs/ysig/yatesig.h b/libs/ysig/yatesig.h index e3b6a214..c6b733b1 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -5089,6 +5089,13 @@ public: inline bool inhibited(int flags) const { return (m_inhibited & flags) != 0; } + /** + * Get the current congestion level of the link + * @return Congestion level, 0 if not congested, 3 if maximum congestion + */ + virtual unsigned int congestion() + { return m_congestion; } + /** * Get the sequence number of the last MSU received * @return Last FSN received, negative if not available @@ -5118,7 +5125,7 @@ protected: * Constructor */ inline SS7Layer2() - : m_autoEmergency(true), m_lastSeqRx(-1), + : m_autoEmergency(true), m_lastSeqRx(-1), m_congestion(0), m_l2userMutex(true,"SS7Layer2::l2user"), m_l2user(0), m_sls(-1), m_checkTime(0), m_checkFail(false), m_inhibited(Unchecked) { } @@ -5187,6 +5194,11 @@ protected: */ int m_lastSeqRx; + /** + * Current congestion level + */ + unsigned int m_congestion; + private: Mutex m_l2userMutex; SS7L2User* m_l2user; @@ -5234,7 +5246,7 @@ public: inline SS7Route(unsigned int packed, unsigned int priority = 0, unsigned int shift = 0) : Mutex(true,"SS7Route"), m_packed(packed), m_priority(priority), m_shift(shift), - m_state(Unknown) + m_state(Unknown), m_congCount(0), m_congBytes(0) { m_networks.setDelete(false); } /** @@ -5244,7 +5256,8 @@ public: inline SS7Route(const SS7Route& original) : Mutex(true,"SS7Route"), m_packed(original.packed()), m_priority(original.priority()), - m_shift(original.shift()), m_state(original.state()) + m_shift(original.shift()), m_state(original.state()), + m_congCount(0), m_congBytes(0) { m_networks.setDelete(false); } /** @@ -5343,12 +5356,20 @@ public: int transmitMSU(const SS7Router* router, const SS7MSU& msu, const SS7Label& label, int sls, const SS7Layer3* source = 0); + /** + * Check the current congestion status according to Q.704 11.2.3.1 + * @return True if a TFC should be sent + */ + bool congested(); + private: unsigned int m_packed; // Packed destination point code unsigned int m_priority; // Network priority for the given destination (used by SS7Layer3) unsigned int m_shift; // SLS right shift when selecting linkset ObjList m_networks; // List of networks used to route to the given destination (used by SS7Router) State m_state; // State of the route + unsigned int m_congCount; // Congestion event count + unsigned int m_congBytes; // Congestion MSU bytes count }; /** @@ -5491,6 +5512,14 @@ public: virtual bool inhibit(int sls, int setFlags, int clrFlags = 0) { return false; } + /** + * Get the current congestion level of a link + * @param sls Signalling Link to check for congestion, -1 for maximum + * @return Congestion level, 0 if not congested, 3 if maximum congestion + */ + virtual unsigned int congestion(int sls) + { return 0; } + /** * Get the sequence number of the last MSU received on a link * @param sls Signalling Link to retrieve MSU number from @@ -6206,6 +6235,7 @@ private: unsigned long m_rxMsu; unsigned long m_txMsu; unsigned long m_fwdMsu; + unsigned long m_congestions; SS7Management* m_mngmt; }; @@ -6828,6 +6858,13 @@ public: */ virtual bool inhibit(int sls, int setFlags, int clrFlags = 0); + /** + * Get the current congestion level of a link + * @param sls Signalling Link to check for congestion, -1 for maximum + * @return Congestion level, 0 if not congested, 3 if maximum congestion + */ + virtual unsigned int congestion(int sls); + /** * Get the sequence number of the last MSU received on a link * @param sls Signalling Link to retrieve MSU number from