MTP3 now fully obeys Q.707 Link Maintenance and implements both T1 and T2.
SLTx are checked for point codes and SLS, SLTA verifies test pattern. git-svn-id: http://voip.null.ro/svn/yate@3613 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
76e918e444
commit
3c35a5505b
|
@ -471,14 +471,18 @@
|
|||
; autostart: bool: Automatically enable the linkset at startup
|
||||
;autostart=yes
|
||||
|
||||
; maintenance: integer: Interval in msec for sending SLTM messages (Q.707 T2)
|
||||
; A value of zero disables sending SLTM else it is clamped to range 5s - 10m
|
||||
;maintenance=60000
|
||||
|
||||
; checklinks: boolean: Check that the links answer to maintenance messages
|
||||
; (SLTM/SLTA) before placing them into service (normal behavior)
|
||||
;checklinks=true
|
||||
|
||||
; checkfails: integer: Interval in msec for resending SLTM messages (Q.707 T1)
|
||||
; A value of zero disables link fail else the value is clamped between 4s - 12s
|
||||
;checkfails=5000
|
||||
|
||||
; maintenance: integer: Interval in msec for sending SLTM messages (Q.707 T2)
|
||||
; A value of zero disables periodic SLTM else it is clamped to range 30s - 5m
|
||||
;maintenance=60000
|
||||
|
||||
; layer3dump: string: Filename to dump MTP3 packets to
|
||||
;layer3dump=
|
||||
|
||||
|
|
|
@ -277,10 +277,21 @@ bool SS7Layer3::maintenance(const SS7MSU& msu, const SS7Label& label, int sls)
|
|||
addr << SS7PointCode::lookup(label.type()) << "," << label;
|
||||
if (debugAt(DebugAll))
|
||||
addr << " (" << label.opc().pack(label.type()) << ":" << label.dpc().pack(label.type()) << ":" << label.sls() << ")";
|
||||
bool badLink = label.sls() != sls;
|
||||
if (!badLink) {
|
||||
unsigned int local = getLocal(label.type());
|
||||
// maintenance messages must be addressed to us
|
||||
if (local && label.dpc().pack(label.type()) != local)
|
||||
badLink = true;
|
||||
// and come from an adjacent node
|
||||
else if (getRoutePriority(label.type(),label.opc()))
|
||||
badLink = true;
|
||||
}
|
||||
int level = DebugInfo;
|
||||
if (label.sls() != sls) {
|
||||
if (badLink) {
|
||||
addr << " on " << sls;
|
||||
level = DebugMild;
|
||||
badLink = true;
|
||||
}
|
||||
unsigned char len = s[1] >> 4;
|
||||
// get a pointer to the test pattern
|
||||
|
@ -292,13 +303,16 @@ bool SS7Layer3::maintenance(const SS7MSU& msu, const SS7Label& label, int sls)
|
|||
}
|
||||
switch (s[0]) {
|
||||
case SS7MsgMTN::SLTM:
|
||||
Debug(this,level,"Received SLTM %s with %u bytes",addr.c_str(),len);
|
||||
if (badLink)
|
||||
return false;
|
||||
{
|
||||
Debug(this,level,"Received SLTM %s with %u bytes",addr.c_str(),len);
|
||||
SS7Label lbl(label,label.sls(),0);
|
||||
SS7MSU answer(msu.getSIO(),lbl,0,len+2);
|
||||
unsigned char* d = answer.getData(lbl.length()+1,len+2);
|
||||
if (!d)
|
||||
return false;
|
||||
linkChecked(sls,true);
|
||||
Debug(this,DebugInfo,"Sending SLTA %s with %u bytes",addr.c_str(),len);
|
||||
*d++ = SS7MsgMTN::SLTA;
|
||||
*d++ = len << 4;
|
||||
|
@ -308,7 +322,17 @@ bool SS7Layer3::maintenance(const SS7MSU& msu, const SS7Label& label, int sls)
|
|||
}
|
||||
return true;
|
||||
case SS7MsgMTN::SLTA:
|
||||
Debug(this,level,"Received SLTM %s with %u bytes",addr.c_str(),len);
|
||||
Debug(this,level,"Received SLTA %s with %u bytes",addr.c_str(),len);
|
||||
if (badLink)
|
||||
return false;
|
||||
if (len != 4)
|
||||
return false;
|
||||
unsigned char patt = sls;
|
||||
patt = (patt << 4) | (patt & 0x0f);
|
||||
while (len--)
|
||||
if (*t++ != patt++)
|
||||
return false;
|
||||
linkChecked(sls,false);
|
||||
return true;
|
||||
}
|
||||
Debug(this,DebugMild,"Received MTN %s type %02X, length %u [%p]",
|
||||
|
@ -528,7 +552,8 @@ SS7MTP3::SS7MTP3(const NamedList& params)
|
|||
: SignallingComponent(params.safe("SS7MTP3"),¶ms),
|
||||
SignallingDumpable(SignallingDumper::Mtp3),
|
||||
Mutex(true,"SS7MTP3"),
|
||||
m_total(0), m_active(0), m_inhibit(false), m_checklinks(true), m_check(0)
|
||||
m_total(0), m_active(0), m_inhibit(false),
|
||||
m_checklinks(true), m_checkT1(0), m_checkT2(0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (debugAt(DebugAll)) {
|
||||
|
@ -569,14 +594,22 @@ SS7MTP3::SS7MTP3(const NamedList& params)
|
|||
Debug(this,level,"Point code types are '%s' [%p]",stype.safe(),this);
|
||||
|
||||
m_inhibit = !params.getBoolValue("autostart",true);
|
||||
m_checklinks = params.getBoolValue("checklinks",true);
|
||||
int check = params.getIntValue("maintenance",60000);
|
||||
m_checklinks = params.getBoolValue("checklinks",m_checklinks);
|
||||
int check = params.getIntValue("checkfails",5000);
|
||||
if (check > 0) {
|
||||
if (check < 5000)
|
||||
check = 5000;
|
||||
else if (check > 600000)
|
||||
check = 600000;
|
||||
m_check = 1000 * check;
|
||||
if (check < 4000)
|
||||
check = 4000;
|
||||
else if (check > 12000)
|
||||
check = 12000;
|
||||
m_checkT1 = 1000 * check;
|
||||
}
|
||||
check = params.getIntValue("maintenance",60000);
|
||||
if (check > 0) {
|
||||
if (check < 30000)
|
||||
check = 30000;
|
||||
else if (check > 300000)
|
||||
check = 300000;
|
||||
m_checkT2 = 1000 * check;
|
||||
}
|
||||
buildRoutes(params);
|
||||
setDumper(params.getValue("layer3dump"));
|
||||
|
@ -980,13 +1013,14 @@ bool SS7MTP3::receivedMSU(const SS7MSU& msu, SS7Layer2* link, int sls)
|
|||
SS7PointCode::Type cpType = type(netType);
|
||||
unsigned int llen = SS7Label::length(cpType);
|
||||
if (!llen) {
|
||||
Debug(toString(),DebugWarn,"Received MSU but point code type is unconfigured [%p]",this);
|
||||
Debug(toString(),DebugWarn,"Received %s MSU, point code type unknown [%p]",
|
||||
msu.getIndicatorName(),this);
|
||||
return false;
|
||||
}
|
||||
// check MSU length against SIO + label length
|
||||
if (msu.length() <= llen) {
|
||||
Debug(this,DebugMild,"Received short MSU of length %u [%p]",
|
||||
msu.length(),this);
|
||||
Debug(this,DebugMild,"Received on %d short MSU of length %u [%p]",
|
||||
sls,msu.length(),this);
|
||||
return false;
|
||||
}
|
||||
SS7Label label(cpType,msu);
|
||||
|
@ -1003,11 +1037,6 @@ bool SS7MTP3::receivedMSU(const SS7MSU& msu, SS7Layer2* link, int sls)
|
|||
if (link->inhibited(SS7Layer2::Unchecked)) {
|
||||
if (!maint)
|
||||
return false;
|
||||
if (label.sls() == sls) {
|
||||
Debug(this,DebugNote,"Placing link %d '%s' in service, inhibitions 0x%02X [%p]",
|
||||
sls,link->toString().c_str(),link->inhibited(),this);
|
||||
link->inhibit(0,SS7Layer2::Unchecked);
|
||||
}
|
||||
}
|
||||
if (!maint && (msu.getSIF() != SS7MSU::SNM) &&
|
||||
link->inhibited(SS7Layer2::Unchecked|SS7Layer2::Inactive|SS7Layer2::Local)) {
|
||||
|
@ -1078,9 +1107,10 @@ void SS7MTP3::notify(SS7Layer2* link)
|
|||
if (link) {
|
||||
if (link->operational()) {
|
||||
if (link->inhibited(SS7Layer2::Unchecked)) {
|
||||
u_int64_t t = Time::now() + 50000 + (::random() % 100000);
|
||||
if ((t < link->m_check) || (t - 4000000 > link->m_check))
|
||||
link->m_check = t;
|
||||
// initiate a slightly delayed SLTM check
|
||||
u_int64_t t = Time::now() + 100000;
|
||||
if ((link->m_checkTime > t) || (t - 2000000 > link->m_checkTime))
|
||||
link->m_checkTime = t;
|
||||
}
|
||||
else if (link->inhibited(SS7Layer2::Inactive))
|
||||
act = (unsigned int)-1;
|
||||
|
@ -1147,8 +1177,27 @@ void SS7MTP3::timerTick(const Time& when)
|
|||
if (!p)
|
||||
continue;
|
||||
SS7Layer2* l2 = *p;
|
||||
if (l2 && l2->m_check && (l2->m_check < when) && l2->operational()) {
|
||||
l2->m_check = m_check ? when + m_check : 0;
|
||||
if (l2 && l2->m_checkTime && (l2->m_checkTime < when) && l2->operational()) {
|
||||
l2->m_checkTime = 0;
|
||||
u_int64_t check = m_checkT2;
|
||||
if (l2->m_checkFail) {
|
||||
l2->m_checkFail = false;
|
||||
if (!l2->inhibited(SS7Layer2::Unchecked)) {
|
||||
Debug(this,DebugWarn,"Taking link %d '%s' out of service [%p]",
|
||||
l2->sls(),l2->toString().c_str(),this);
|
||||
l2->inhibit(SS7Layer2::Unchecked);
|
||||
if (m_checkT1)
|
||||
check = m_checkT1;
|
||||
}
|
||||
}
|
||||
else if (m_checkT1) {
|
||||
l2->m_checkFail = true;
|
||||
check = m_checkT1;
|
||||
}
|
||||
// if some action set a new timer bail out, we'll get back to it
|
||||
if (l2->m_checkTime)
|
||||
continue;
|
||||
l2->m_checkTime = check ? when + check : 0;
|
||||
for (unsigned int i = 0; i < YSS7_PCTYPE_COUNT; i++) {
|
||||
SS7PointCode::Type type = (SS7PointCode::Type)(i + 1);
|
||||
unsigned int local = getLocal(type);
|
||||
|
@ -1190,4 +1239,37 @@ void SS7MTP3::timerTick(const Time& when)
|
|||
}
|
||||
}
|
||||
|
||||
void SS7MTP3::linkChecked(int sls, bool remote)
|
||||
{
|
||||
if (sls < 0)
|
||||
return;
|
||||
const ObjList* l = &m_links;
|
||||
for (; l; l = l->next()) {
|
||||
L2Pointer* p = static_cast<L2Pointer*>(l->get());
|
||||
if (!p)
|
||||
continue;
|
||||
SS7Layer2* l2 = *p;
|
||||
if (!l2 || (l2->sls() != sls))
|
||||
continue;
|
||||
if (remote) {
|
||||
if (l2->inhibited(SS7Layer2::Unchecked)) {
|
||||
// trigger a slightly delayed SLTM check
|
||||
u_int64_t t = Time::now() + 100000;
|
||||
if ((l2->m_checkTime > t) || (t - 4000000 > l2->m_checkTime))
|
||||
l2->m_checkTime = t;
|
||||
}
|
||||
}
|
||||
else {
|
||||
l2->m_checkFail = false;
|
||||
l2->m_checkTime = m_checkT2 ? Time::now() + m_checkT2 : 0;
|
||||
if (l2->inhibited(SS7Layer2::Unchecked)) {
|
||||
Debug(this,DebugNote,"Placing link %d '%s' in service [%p]",
|
||||
sls,l2->toString().c_str(),this);
|
||||
l2->inhibit(0,SS7Layer2::Unchecked);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -5120,7 +5120,7 @@ protected:
|
|||
inline SS7Layer2()
|
||||
: m_autoEmergency(true), m_lastSeqRx(-1),
|
||||
m_l2userMutex(true,"SS7Layer2::l2user"), m_l2user(0), m_sls(-1),
|
||||
m_check(0), m_inhibited(Unchecked)
|
||||
m_checkTime(0), m_checkFail(false), m_inhibited(Unchecked)
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
@ -5191,7 +5191,8 @@ private:
|
|||
Mutex m_l2userMutex;
|
||||
SS7L2User* m_l2user;
|
||||
int m_sls;
|
||||
u_int64_t m_check;
|
||||
u_int64_t m_checkTime;
|
||||
bool m_checkFail;
|
||||
int m_inhibited;
|
||||
};
|
||||
|
||||
|
@ -5682,7 +5683,7 @@ protected:
|
|||
|
||||
/**
|
||||
* Notify out user part about a status change
|
||||
* @param sls Signallink Link that generated the notification, -1 if none
|
||||
* @param sls Link that generated the notification, -1 if none
|
||||
*/
|
||||
inline void notify(int sls = -1)
|
||||
{
|
||||
|
@ -5693,6 +5694,14 @@ protected:
|
|||
tmp->notify(this,sls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called from maintenance when valid SLTA or SLTM are received
|
||||
* @param sls Link that was checked by maintenance
|
||||
* @param remote True if remote checked the link, false if local success
|
||||
*/
|
||||
virtual void linkChecked(int sls, bool remote)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Default processing of a MTN (Maintenance MSU)
|
||||
* @param msu Message data, starting with Service Indicator Octet
|
||||
|
@ -6880,6 +6889,13 @@ protected:
|
|||
*/
|
||||
virtual void timerTick(const Time& when);
|
||||
|
||||
/**
|
||||
* Callback called from maintenance when valid SLTA or SLTM are received
|
||||
* @param sls Link that was checked by maintenance
|
||||
* @param remote True if remote checked the link, false if local success
|
||||
*/
|
||||
virtual void linkChecked(int sls, bool remote);
|
||||
|
||||
/**
|
||||
* Process a MSU received from the Layer 2 component
|
||||
* @param msu Message data, starting with Service Indicator Octet
|
||||
|
@ -6923,8 +6939,9 @@ private:
|
|||
bool m_inhibit;
|
||||
// check the links before placing them in service
|
||||
bool m_checklinks;
|
||||
// maintenance check interval
|
||||
u_int64_t m_check;
|
||||
// maintenance check intervals (Q.707)
|
||||
u_int64_t m_checkT1;
|
||||
u_int64_t m_checkT2;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue