improved detection of changes in topology, fixed problem with stalled topology inform...
authorVictor Kirhenshtein <victor@netxms.org>
Fri, 17 Oct 2014 14:07:42 +0000 (17:07 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Fri, 17 Oct 2014 14:07:42 +0000 (17:07 +0300)
ChangeLog
include/nxclapi.h
src/server/core/cdp.cpp
src/server/core/interface.cpp
src/server/core/lldp.cpp
src/server/core/ndp.cpp
src/server/core/node.cpp
src/server/include/nms_objects.h
src/server/include/nms_topo.h

index fda2a95..ac6a645 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,7 @@
 - New methods in NXSL classes Node, Interface, and NetObj: setStatusCalculation and setStatusPropagation
 - New attributes "slot" and "port" in NXSL class Interface
 - Can execute arbitrary NXSL script in context of node, cluster, subnet, or container object from management console
+- Improved network topology changes detection
 - Management console:
     - Can show alarms for multiple selected objects
     - Fixed non-working ordering in event list in alarm details view
index 9c1867d..0245b68 100644 (file)
@@ -269,6 +269,7 @@ typedef void * NXC_SESSION;
 #define IF_EXCLUDE_FROM_TOPOLOGY 0x00000004
 #define IF_LOOPBACK              0x00000008
 #define IF_CREATED_MANUALLY      0x00000010
+#define IF_PEER_REFLECTION       0x00000020  /* topology information obtained by reflection */
 #define IF_EXPECTED_STATE_MASK   0x30000000    /* 2-bit field holding expected interface state */
 #define IF_USER_FLAGS_MASK       (IF_EXCLUDE_FROM_TOPOLOGY)    /* flags that can be changed by user */
 
index ed99af8..9d1434d 100644 (file)
@@ -76,6 +76,7 @@ static UINT32 CDPTopoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Transp
                                info.objectId = remoteNode->Id();
                                info.isPtToPt = true;
                                info.protocol = LL_PROTO_CDP;
+            info.isCached = false;
 
                                ((LinkLayerNeighbors *)arg)->addConnection(&info);
                        }
index a9ee29d..0781d98 100644 (file)
@@ -890,14 +890,26 @@ void Interface::onObjectDelete(UINT32 dwObjectId)
 /**
  * Set peer information
  */
-void Interface::setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol)
+void Interface::setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol, bool reflection)
 {
    if ((m_peerNodeId == node->Id()) && (m_peerInterfaceId == iface->Id()) && (m_peerDiscoveryProtocol == protocol))
+   {
+      if ((m_flags & IF_PEER_REFLECTION) && !reflection)
+      {
+         // set peer information as confirmed
+         m_flags &= ~IF_PEER_REFLECTION;
+         Modify();
+      }
       return;
+   }
 
    m_peerNodeId = node->Id();
    m_peerInterfaceId = iface->Id();
    m_peerDiscoveryProtocol = protocol;
+   if (reflection)
+      m_flags |= IF_PEER_REFLECTION;
+   else
+      m_flags &= ~IF_PEER_REFLECTION;
    Modify();
    if (!m_isSystem)
    {
index deca152..1b2b042 100644 (file)
@@ -195,6 +195,7 @@ static UINT32 LLDPTopoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Trans
                        info.ifRemote = (ifRemote != NULL) ? ifRemote->getIfIndex() : 0;
                        info.isPtToPt = true;
                        info.protocol = LL_PROTO_LLDP;
+         info.isCached = false;
 
                        // Index to lldpRemTable is lldpRemTimeMark, lldpRemLocalPortNum, lldpRemIndex
                        UINT32 localPort = oid->getValue()[oid->getLength() - 2];
index 371da25..6676e88 100644 (file)
@@ -99,6 +99,7 @@ static UINT32 NDPTopoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Transp
                                info.ifLocal = ifLocal->getIfIndex();
                                info.isPtToPt = true;
                                info.protocol = LL_PROTO_NDP;
+            info.isCached = false;
                                ((LinkLayerNeighbors *)arg)->addConnection(&info);
                        }
                }
index 059ae38..dbc9049 100644 (file)
@@ -5265,6 +5265,9 @@ void Node::topologyPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller)
                for(int i = 0; i < nbs->size(); i++)
                {
                        LL_NEIGHBOR_INFO *ni = nbs->getConnection(i);
+         if (ni->isCached)
+            continue;   // ignore cached information
+
                        NetObj *object = FindObjectById(ni->objectId);
                        if ((object != NULL) && (object->Type() == OBJECT_NODE))
                        {
@@ -5295,8 +5298,8 @@ void Node::topologyPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller)
                                                }
                                        }
 
-               ifLocal->setPeer((Node *)object, ifRemote, ni->protocol);
-               ifRemote->setPeer(this, ifLocal, ni->protocol);
+               ifLocal->setPeer((Node *)object, ifRemote, ni->protocol, false);
+               ifRemote->setPeer(this, ifLocal, ni->protocol, true);
                                        sendPollerMsg(dwRqId, _T("   Local interface %s linked to remote interface %s:%s\r\n"),
                                                      ifLocal->Name(), object->Name(), ifRemote->Name());
                                        DbgPrintf(5, _T("Local interface %s:%s linked to remote interface %s:%s"),
@@ -5322,32 +5325,29 @@ void Node::topologyPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller)
          // Remove outdated peer information
          else if (iface->getPeerNodeId() != 0)
          {
-            bool nodeFound = false;
+            Node *peerNode = (Node *)FindObjectById(iface->getPeerNodeId(), OBJECT_NODE);
+            if (peerNode->isDown())
+               continue; // Don't change information about down peers
+
             bool ifaceFound = false;
-                     for(int j = 0; j < nbs->size(); j++)
-                     {
-                             LL_NEIGHBOR_INFO *ni = nbs->getConnection(j);
-               if (ni->objectId == iface->getPeerNodeId())
+                for(int j = 0; j < nbs->size(); j++)
+                {
+                        LL_NEIGHBOR_INFO *ni = nbs->getConnection(j);
+               if ((ni->objectId == iface->getPeerNodeId()) && (ni->ifLocal == iface->getIfIndex()))
                {
-                  nodeFound = true;
-                  if (ni->ifLocal == iface->getIfIndex())
-                  {
-                     ifaceFound = true;
-                     break;
-                  }
+                  bool reflection = (iface->getFlags() & IF_PEER_REFLECTION) ? true : false;
+                  ifaceFound = !ni->isCached || (((ni->protocol == LL_PROTO_FDB) || (ni->protocol == LL_PROTO_STP)) && reflection);
+                  break;
                }
             }
 
-            // Only remove information from interfaces where peer node
-            // found but interface not which means that connectivity information was changed.
-            // If node is not found at all it may just mean that it is down at the moment.
-            if (nodeFound && !ifaceFound)
+            if (!ifaceFound)
             {
-                                       Interface *ifPeer = (Interface *)FindObjectById(iface->getPeerInterfaceId(), OBJECT_INTERFACE);
-                                       if (ifPeer != NULL)
-                                       {
-                                               ifPeer->clearPeer();
-                                       }
+                                  Interface *ifPeer = (Interface *)FindObjectById(iface->getPeerInterfaceId(), OBJECT_INTERFACE);
+                                  if (ifPeer != NULL)
+                                  {
+                                          ifPeer->clearPeer();
+                                  }
                iface->clearPeer();
                DbgPrintf(6, _T("Node::topologyPoll(%s [%d]): Removed outdated peer information from interface %s [%d]"), m_szName, m_dwId, iface->Name(), iface->Id());
             }
@@ -5503,6 +5503,7 @@ void Node::addExistingConnections(LinkLayerNeighbors *nbs)
                                info.objectId = ifLocal->getPeerNodeId();
                                info.isPtToPt = true;
             info.protocol = ifLocal->getPeerDiscoveryProtocol();
+            info.isCached = true;
                                nbs->addConnection(&info);
                        }
                }
index 61e35d2..5f02479 100644 (file)
@@ -691,7 +691,7 @@ public:
    void setPortNumber(UINT32 port) { m_portNumber = port; Modify(); }
        void setPhysicalPortFlag(bool isPhysical) { if (isPhysical) m_flags |= IF_PHYSICAL_PORT; else m_flags &= ~IF_PHYSICAL_PORT; Modify(); }
        void setManualCreationFlag(bool isManual) { if (isManual) m_flags |= IF_CREATED_MANUALLY; else m_flags &= ~IF_CREATED_MANUALLY; Modify(); }
-       void setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol);
+       void setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol, bool reflection);
    void clearPeer() { m_peerNodeId = 0; m_peerInterfaceId = 0; m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN; Modify(); }
    void setDescription(const TCHAR *descr) { LockData(); nx_strncpy(m_description, descr, MAX_DB_STRING); Modify(); UnlockData(); }
 
@@ -1127,7 +1127,7 @@ public:
        WORD getAuthMethod() { return m_wAuthMethod; }
        const TCHAR *getSharedSecret() { return m_szSharedSecret; }
 
-   BOOL isDown() { return m_dwDynamicFlags & NDF_UNREACHABLE ? TRUE : FALSE; }
+   bool isDown() { return (m_dwDynamicFlags & NDF_UNREACHABLE) ? true : false; }
        time_t getDownTime() const { return m_downSince; }
 
    void addInterface(Interface *pInterface) { AddChild(pInterface); pInterface->AddParent(this); }
index 2b75b76..6479154 100644 (file)
@@ -166,6 +166,7 @@ struct LL_NEIGHBOR_INFO
        UINT32 objectId;                       // ID of connected object
        bool isPtToPt;                         // true if this is point-to-point link
        LinkLayerProtocol protocol; // Protocol used to obtain information
+   bool isCached;              // true if this is cached information
 };
 
 /**