- Implemented routing table caching
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 26 Jul 2005 07:00:05 +0000 (07:00 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 26 Jul 2005 07:00:05 +0000 (07:00 +0000)
- Implemented event correlation for SYS_NODE_DOWN to SYS_NODE_DOWN or SYS_IF_DOWN from intermediate nodes (routers)

16 files changed:
.gitattributes
ChangeLog
sql/setup.in
src/server/core/correlate.cpp
src/server/core/interface.cpp
src/server/core/main.cpp
src/server/core/node.cpp
src/server/core/nxcore.dsp
src/server/core/poll.cpp
src/server/core/snmp.cpp
src/server/core/tracert.cpp
src/server/include/nms_core.h
src/server/include/nms_events.h
src/server/include/nms_objects.h
src/server/include/nms_topo.h [copied from src/server/core/tracert.cpp with 64% similarity]
src/server/libnxsrv/agent.cpp

index bfd6533..c046c8a 100644 (file)
@@ -774,6 +774,7 @@ src/server/include/nms_events.h -text
 src/server/include/nms_locks.h -text
 src/server/include/nms_objects.h -text
 src/server/include/nms_pkg.h -text
+src/server/include/nms_topo.h -text
 src/server/include/nms_users.h -text
 src/server/include/nxmodule.h -text
 src/server/include/nxsrvapi.h -text
index be09938..c231faa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
 * 0.2.3
 *
 
+- Implemented basic event correlation
 - Windows agent: implemented enum Net.IP.RoutingTable
 - Fixed issues: 29
 
index 223628e..ac95b4f 100644 (file)
@@ -27,6 +27,8 @@ INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('ConfigurationPollingInterval','3600',1,1);
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RoutingTableUpdateInterval','300',1,1);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('ResolveNodeNames','1',1,0);
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('NumberOfEventProcessors','1',1,1);
@@ -41,6 +43,8 @@ INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('NumberOfDiscoveryPollers','1',1,1);
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('NumberOfRoutingTablePollers','5',1,1);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
 #ifdef DB_MYSQL
        VALUES ('IDataTableCreationCommand','CREATE TABLE idata_%ld (item_id integer not null,idata_timestamp integer,idata_value varchar(255)) TYPE=InnoDB',0,1);
 #else
index fe00269..f310a9e 100644 (file)
 
 
 //
+// Correlate SYS_NODE_DOWN event
+//
+
+static void C_SysNodeDown(Node *pNode, Event *pEvent)
+{
+   NETWORK_PATH_TRACE *pTrace;
+   Node *pMgmtNode;
+   Interface *pInterface;
+   int i;
+
+   // Trace route from management station to failed node and
+   // check for failed intermediate nodes or interfaces
+   pMgmtNode = (Node *)FindObjectById(g_dwMgmtNode);
+   if (pMgmtNode != NULL)
+   {
+      pTrace = TraceRoute(pMgmtNode, pNode);
+      if (pTrace != NULL)
+      {
+         for(i = 0; i < pTrace->iNumHops; i++)
+         {
+            if ((pTrace->pHopList[i].pObject != NULL) &&
+                (pTrace->pHopList[i].pObject != pNode))
+            {
+               if (pTrace->pHopList[i].pObject->Type() == OBJECT_NODE)
+               {
+                  if (((Node *)pTrace->pHopList[i].pObject)->IsDown())
+                  {
+                     pEvent->SetRootId(((Node *)pTrace->pHopList[i].pObject)->GetLastEventId(LAST_EVENT_NODE_DOWN));
+                  }
+                  else
+                  {
+                     pInterface = ((Node *)pTrace->pHopList[i].pObject)->FindInterface(pTrace->pHopList[i].dwIfIndex, INADDR_ANY);
+                     if (pInterface != NULL)
+                     {
+                        if (pInterface->Status() == STATUS_CRITICAL)
+                        {
+                           pEvent->SetRootId(pInterface->GetLastDownEventId());
+                        }
+                     }
+                  }
+               }
+            }
+         }
+         DestroyTraceData(pTrace);
+      }
+   }
+}
+
+
+//
 // Correlate event
 //
 
 void CorrelateEvent(Event *pEvent)
 {
    NetObj *pObject;
+   Interface *pInterface;
 
    pObject = FindObjectById(pEvent->SourceId());
    if ((pObject != NULL) && (pObject->Type() == OBJECT_NODE))
    {
       switch(pEvent->Code())
       {
-         case EVENT_SERVICE_DOWN:
          case EVENT_INTERFACE_DOWN:
+            pInterface = ((Node *)pObject)->FindInterface(pEvent->GetParameterAsULong(4), INADDR_ANY);
+            if (pInterface != NULL)
+            {
+               pInterface->SetLastDownEventId(pEvent->Id());
+            }
+         case EVENT_SERVICE_DOWN:
          case EVENT_SNMP_FAIL:
          case EVENT_AGENT_FAIL:
             if (((Node *)pObject)->RuntimeFlags() & NDF_UNREACHEABLE)
@@ -47,6 +103,7 @@ void CorrelateEvent(Event *pEvent)
             break;
          case EVENT_NODE_DOWN:
             ((Node *)pObject)->SetLastEventId(LAST_EVENT_NODE_DOWN, pEvent->Id());
+            C_SysNodeDown((Node *)pObject, pEvent);
             break;
          case EVENT_NODE_UP:
             ((Node *)pObject)->SetLastEventId(LAST_EVENT_NODE_DOWN, 0);
index bbbae60..4a56713 100644 (file)
@@ -33,6 +33,7 @@ Interface::Interface()
    m_dwIpNetMask = 0;
    m_dwIfIndex = 0;
    m_dwIfType = IFTYPE_OTHER;
+   m_qwLastDownEventId = 0;
 }
 
 
@@ -49,6 +50,7 @@ Interface::Interface(DWORD dwAddr, DWORD dwNetMask)
    m_dwIfIndex = 1;
    m_dwIfType = IFTYPE_OTHER;
    memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
+   m_qwLastDownEventId = 0;
    m_bIsHidden = TRUE;
 }
 
@@ -66,6 +68,7 @@ Interface::Interface(char *szName, DWORD dwIndex, DWORD dwAddr, DWORD dwNetMask,
    m_dwIpAddr = dwAddr;
    m_dwIpNetMask = dwNetMask;
    memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
+   m_qwLastDownEventId = 0;
    m_bIsHidden = TRUE;
 }
 
index 82023b0..6edffdb 100644 (file)
@@ -67,6 +67,7 @@ DB_HANDLE g_hCoreDB = 0;
 DWORD g_dwDiscoveryPollingInterval;
 DWORD g_dwStatusPollingInterval;
 DWORD g_dwConfigurationPollingInterval;
+DWORD g_dwRoutingTableUpdateInterval;
 int g_iStatusAlgorithm = SA_WORST_STATUS;
 char g_szDataDir[MAX_PATH];
 DWORD g_dwDBSyntax = DB_SYNTAX_GENERIC;
@@ -171,6 +172,7 @@ static void LoadGlobalConfig()
    g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
    g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
    g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
+   g_dwRoutingTableUpdateInterval = ConfigReadInt("RoutingTableUpdateInterval", 300);
    if (ConfigReadInt("EnableAccessControl", 1))
       g_dwFlags |= AF_ENABLE_ACCESS_CONTROL;
    if (ConfigReadInt("EnableEventsAccessControl", 1))
@@ -644,6 +646,58 @@ BOOL ProcessConsoleCommand(char *pszCmdLine, CONSOLE_CTX pCtx)
       {
          ShowPollerState(pCtx);
       }
+      else if (IsCommand("ROUTING-TABLE", szBuffer, 1))
+      {
+         DWORD dwNode;
+         NetObj *pObject;
+
+         pArg = ExtractWord(pArg, szBuffer);
+         dwNode = strtoul(szBuffer, NULL, 0);
+         if (dwNode != 0)
+         {
+            pObject = FindObjectById(dwNode);
+            if (pObject != NULL)
+            {
+               if (pObject->Type() == OBJECT_NODE)
+               {
+                  ROUTING_TABLE *pRT;
+                  char szIpAddr[16];
+                  int i;
+
+                  ConsolePrintf(pCtx, "Routing table for node %s:\n\n", pObject->Name());
+                  pRT = ((Node *)pObject)->GetCachedRoutingTable();
+                  if (pRT != NULL)
+                  {
+                     for(i = 0; i < pRT->iNumEntries; i++)
+                     {
+                        sprintf(szBuffer, "%s/%d", IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
+                                BitsInMask(pRT->pRoutes[i].dwDestMask));
+                        ConsolePrintf(pCtx, "%-18s %-15s %-6ld %ld\n", szBuffer,
+                                      IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
+                                      pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
+                     }
+                     ConsolePrintf(pCtx, "\n");
+                  }
+                  else
+                  {
+                     ConsolePrintf(pCtx, "Node doesn't have cached routing table\n\n");
+                  }
+               }
+               else
+               {
+                  ConsolePrintf(pCtx, "ERROR: Object is not a node\n\n");
+               }
+            }
+            else
+            {
+               ConsolePrintf(pCtx, "ERROR: Object with ID %ld does not exist\n\n", dwNode);
+            }
+         }
+         else
+         {
+            ConsolePrintf(pCtx, "ERROR: Invalid or missing node ID\n\n");
+         }
+      }
       else if (IsCommand("SESSIONS", szBuffer, 2))
       {
          DumpSessions(pCtx);
@@ -669,21 +723,88 @@ BOOL ProcessConsoleCommand(char *pszCmdLine, CONSOLE_CTX pCtx)
             ConsolePrintf(pCtx, "ERROR: Invalid SHOW subcommand\n\n");
       }
    }
+   else if (IsCommand("TRACE", szBuffer, 1))
+   {
+      DWORD dwNode1, dwNode2;
+      NetObj *pObject1, *pObject2;
+      NETWORK_PATH_TRACE *pTrace;
+      char szNextHop[16];
+      int i;
+
+      // Get arguments
+      pArg = ExtractWord(pArg, szBuffer);
+      dwNode1 = strtoul(szBuffer, NULL, 0);
+
+      pArg = ExtractWord(pArg, szBuffer);
+      dwNode2 = strtoul(szBuffer, NULL, 0);
+
+      if ((dwNode1 != 0) && (dwNode2 != 0))
+      {
+         pObject1 = FindObjectById(dwNode1);
+         if (pObject1 == NULL)
+         {
+            ConsolePrintf(pCtx, "ERROR: Object with ID %ld does not exist\n\n", dwNode1);
+         }
+         else
+         {
+            pObject2 = FindObjectById(dwNode2);
+            if (pObject2 == NULL)
+            {
+               ConsolePrintf(pCtx, "ERROR: Object with ID %ld does not exist\n\n", dwNode2);
+            }
+            else
+            {
+               if ((pObject1->Type() == OBJECT_NODE) &&
+                   (pObject2->Type() == OBJECT_NODE))
+               {
+                  pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
+                  if (pTrace != NULL)
+                  {
+                     ConsolePrintf(pCtx, "Trace from %s to %s (%d hops):\n",
+                                   pObject1->Name(), pObject2->Name(), pTrace->iNumHops);
+                     for(i = 0; i < pTrace->iNumHops; i++)
+                        ConsolePrintf(pCtx, "[%ld] %s %s %d\n",
+                                      pTrace->pHopList[i].pObject->Id(),
+                                      pTrace->pHopList[i].pObject->Name(),
+                                      IpToStr(pTrace->pHopList[i].dwNextHop, szNextHop),
+                                      pTrace->pHopList[i].dwIfIndex);
+                     DestroyTraceData(pTrace);
+                     ConsolePrintf(pCtx, "\n");
+                  }
+                  else
+                  {
+                     ConsolePrintf(pCtx, "ERROR: Call to TraceRoute() failed\n\n");
+                  }
+               }
+               else
+               {
+                  ConsolePrintf(pCtx, "ERROR: Object is not a node\n\n");
+               }
+            }
+         }
+      }
+      else
+      {
+         ConsolePrintf(pCtx, "ERROR: Invalid or missing node id(s)\n\n");
+      }
+   }
    else if (IsCommand("HELP", szBuffer, 2) || IsCommand("?", szBuffer, 1))
    {
       ConsolePrintf(pCtx, "Valid commands are:\n"
-                          "   debug [on|off] - Turn debug mode on or off\n"
-                          "   down           - Down NetXMS server\n"
-                          "   exit           - Exit from remote session\n"
-                          "   help           - Display this help\n"
-                          "   show flags     - Show internal server flags\n"
-                          "   show mutex     - Display mutex status\n"
-                          "   show objects   - Dump network objects to screen\n"
-                          "   show pollers   - Show poller threads state information\n"
-                          "   show sessions  - Show active client sessions\n"
-                          "   show stats     - Show server statistics\n"
-                          "   show users     - Show users\n"
-                          "   show watchdog  - Display watchdog information\n"
+                          "   debug [on|off]            - Turn debug mode on or off\n"
+                          "   down                      - Down NetXMS server\n"
+                          "   exit                      - Exit from remote session\n"
+                          "   help                      - Display this help\n"
+                          "   show flags                - Show internal server flags\n"
+                          "   show mutex                - Display mutex status\n"
+                          "   show objects              - Dump network objects to screen\n"
+                          "   show pollers              - Show poller threads state information\n"
+                          "   show routing-table <node> - Show cached routing table for node\n"
+                          "   show sessions             - Show active client sessions\n"
+                          "   show stats                - Show server statistics\n"
+                          "   show users                - Show users\n"
+                          "   show watchdog             - Display watchdog information\n"
+                          "   trace <node1> <node2>     - Show network path trace between two nodes\n"
                           "\nAlmost all commands can be abbreviated to 2 or 3 characters\n"
                           "\n");
    }
index 227c34f..69b64a1 100644 (file)
@@ -45,6 +45,7 @@ Node::Node()
    m_tLastDiscoveryPoll = 0;
    m_tLastStatusPoll = 0;
    m_tLastConfigurationPoll = 0;
+   m_tLastRTUpdate = 0;
    m_hPollerMutex = MutexCreate();
    m_hAgentAccessMutex = MutexCreate();
    m_pAgentConnection = NULL;
@@ -82,6 +83,7 @@ Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags, DWORD dwZone)
    m_tLastDiscoveryPoll = 0;
    m_tLastStatusPoll = 0;
    m_tLastConfigurationPoll = 0;
+   m_tLastRTUpdate = 0;
    m_hPollerMutex = MutexCreate();
    m_hAgentAccessMutex = MutexCreate();
    m_pAgentConnection = NULL;
@@ -523,8 +525,9 @@ Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
          pInterface = (Interface *)m_pChildList[i];
          if (pInterface->IfIndex() == dwIndex)
          {
-            if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
-                (dwHostAddr & pInterface->IpNetMask()))
+            if (((pInterface->IpAddr() & pInterface->IpNetMask()) ==
+                 (dwHostAddr & pInterface->IpNetMask())) ||
+                (dwHostAddr == INADDR_ANY))
             {
                UnlockChildList();
                return pInterface;
@@ -2047,3 +2050,49 @@ ROUTING_TABLE *Node::GetRoutingTable(void)
    }
    return pRT;
 }
+
+
+//
+// Get next hop for given destination address
+//
+
+BOOL Node::GetNextHop(DWORD dwDestAddr, DWORD *pdwNextHop, DWORD *pdwIfIndex)
+{
+   int i;
+   BOOL bResult = FALSE;
+
+   RTLock();
+   if (m_pRoutingTable != NULL)
+   {
+      for(i = 0; i < m_pRoutingTable->iNumEntries; i++)
+         if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
+         {
+            *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
+            *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
+            bResult = TRUE;
+            break;
+         }
+   }
+   RTUnlock();
+
+   return bResult;
+}
+
+
+//
+// Update cached routing table
+//
+
+void Node::UpdateRoutingTable(void)
+{
+   ROUTING_TABLE *pRT;
+
+   pRT = GetRoutingTable();
+   if (pRT != NULL)
+   {
+      RTLock();
+      DestroyRoutingTable(m_pRoutingTable);
+      m_pRoutingTable = pRT;
+      RTUnlock();
+   }
+}
index 8380ace..5804a6b 100644 (file)
@@ -370,6 +370,10 @@ SOURCE=..\..\..\include\nms_threads.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\include\nms_topo.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\include\nms_users.h
 # End Source File
 # Begin Source File
index 471f1b5..4fb37c9 100644 (file)
@@ -43,6 +43,7 @@ struct __poller_state
 
 Queue g_statusPollQueue;
 Queue g_configPollQueue;
+Queue g_routePollQueue;
 Queue g_discoveryPollQueue;
 
 
@@ -241,6 +242,38 @@ static THREAD_RESULT THREAD_CALL ConfigurationPoller(void *arg)
 
 
 //
+// Routing table poll thread
+//
+
+static THREAD_RESULT THREAD_CALL RoutePoller(void *arg)
+{
+   Node *pNode;
+   char szBuffer[MAX_OBJECT_NAME + 64];
+
+   // Initialize state info
+   m_pPollerState[(int)arg].iType = 'R';
+   SetPollerState((int)arg, "init");
+
+   // Main loop
+   while(!ShutdownInProgress())
+   {
+      SetPollerState((int)arg, "wait");
+      pNode = (Node *)g_routePollQueue.GetOrBlock();
+      if (pNode == INVALID_POINTER_VALUE)
+         break;   // Shutdown indicator
+
+      snprintf(szBuffer, MAX_OBJECT_NAME + 64, "poll: %s [%ld]",
+               pNode->Name(), pNode->Id());
+      SetPollerState((int)arg, szBuffer);
+      pNode->UpdateRoutingTable();
+      pNode->DecRefCount();
+   }
+   SetPollerState((int)arg, "finished");
+   return THREAD_OK;
+}
+
+
+//
 // Discovery poll thread
 //
 
@@ -313,34 +346,39 @@ THREAD_RESULT THREAD_CALL NodePollManager(void *pArg)
 {
    Node *pNode;
    DWORD dwWatchdogId;
-   int i, iCounter, iNumStatusPollers, iNumConfigPollers, iNumDiscoveryPollers;
+   int i, iCounter, iNumStatusPollers, iNumConfigPollers;
+   int nIndex, iNumDiscoveryPollers, iNumRoutePollers;
    BOOL bDoNetworkDiscovery;
 
    // Read configuration
    iNumStatusPollers = ConfigReadInt("NumberOfStatusPollers", 10);
    iNumConfigPollers = ConfigReadInt("NumberOfConfigurationPollers", 4);
+   iNumRoutePollers = ConfigReadInt("NumberOfRoutingTablePollers", 5);
    bDoNetworkDiscovery = ConfigReadInt("RunNetworkDiscovery", 1);
    if (bDoNetworkDiscovery)
       iNumDiscoveryPollers = ConfigReadInt("NumberOfDiscoveryPollers", 1);
    else
       iNumDiscoveryPollers = 0;
-   m_iNumPollers = iNumStatusPollers + iNumConfigPollers + iNumDiscoveryPollers;
+   m_iNumPollers = iNumStatusPollers + iNumConfigPollers + iNumDiscoveryPollers + iNumRoutePollers;
 
    // Prepare static data
    m_pPollerState = (__poller_state *)malloc(sizeof(__poller_state) * m_iNumPollers);
 
    // Start status pollers
-   for(i = 0; i < iNumStatusPollers; i++)
-      m_pPollerState[i].handle = ThreadCreateEx(StatusPoller, 0, (void *)i);
+   for(i = 0, nIndex = 0; i < iNumStatusPollers; i++, nIndex++)
+      m_pPollerState[nIndex].handle = ThreadCreateEx(StatusPoller, 0, (void *)nIndex);
 
    // Start configuration pollers
-   for(i = 0; i < iNumConfigPollers; i++)
-      m_pPollerState[i + iNumStatusPollers].handle = ThreadCreateEx(ConfigurationPoller, 0, (void *)(i + iNumStatusPollers));
+   for(i = 0; i < iNumConfigPollers; i++, nIndex++)
+      m_pPollerState[nIndex].handle = ThreadCreateEx(ConfigurationPoller, 0, (void *)nIndex);
+
+   // Start routing table pollers
+   for(i = 0; i < iNumRoutePollers; i++, nIndex++)
+      m_pPollerState[nIndex].handle = ThreadCreateEx(RoutePoller, 0, (void *)nIndex);
 
    // Start discovery pollers
-   for(i = 0; i < iNumDiscoveryPollers; i++)
-      m_pPollerState[i + iNumStatusPollers + iNumConfigPollers].handle = 
-         ThreadCreateEx(DiscoveryPoller, 0, (void *)(i + iNumStatusPollers + iNumConfigPollers));
+   for(i = 0; i < iNumDiscoveryPollers; i++, nIndex++)
+      m_pPollerState[nIndex].handle = ThreadCreateEx(DiscoveryPoller, 0, (void *)nIndex);
 
    dwWatchdogId = WatchdogAddThread("Node Poll Manager", 60);
    iCounter = 0;
@@ -377,6 +415,12 @@ THREAD_RESULT THREAD_CALL NodePollManager(void *pArg)
             pNode->LockForStatusPoll();
             g_statusPollQueue.Put(pNode);
          }
+         if (pNode->ReadyForRoutePoll())
+         {
+            pNode->IncRefCount();
+            pNode->LockForRoutePoll();
+            g_routePollQueue.Put(pNode);
+         }
          if (bDoNetworkDiscovery && pNode->ReadyForDiscoveryPoll())
          {
             pNode->IncRefCount();
@@ -395,6 +439,8 @@ THREAD_RESULT THREAD_CALL NodePollManager(void *pArg)
       g_statusPollQueue.Put(INVALID_POINTER_VALUE);
    for(i = 0; i < iNumConfigPollers; i++)
       g_configPollQueue.Put(INVALID_POINTER_VALUE);
+   for(i = 0; i < iNumRoutePollers; i++)
+      g_routePollQueue.Put(INVALID_POINTER_VALUE);
    for(i = 0; i < iNumDiscoveryPollers; i++)
       g_discoveryPollQueue.Put(INVALID_POINTER_VALUE);
 
index 0c6d907..ce925ad 100644 (file)
@@ -587,7 +587,6 @@ static void HandlerRoute(DWORD dwVersion, DWORD dwAddr, const char *szCommunity,
    if (SnmpGet(dwVersion, dwAddr, szCommunity, NULL, oidName, dwNameLen,
                &route.dwNextHop, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
       return;
-   route.dwNextHop = ntohl(route.dwNextHop);
 
    oidName[dwNameLen - 5] = 8;  // Route type
    if (SnmpGet(dwVersion, dwAddr, szCommunity, NULL, oidName, dwNameLen,
@@ -598,7 +597,6 @@ static void HandlerRoute(DWORD dwVersion, DWORD dwAddr, const char *szCommunity,
    if (SnmpGet(dwVersion, dwAddr, szCommunity, NULL, oidName, dwNameLen,
                &route.dwDestMask, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
       return;
-   route.dwDestMask = ntohl(route.dwDestMask);
 
    ((ROUTING_TABLE *)pArg)->iNumEntries++;
    ((ROUTING_TABLE *)pArg)->pRoutes = 
index d0db790..6091633 100644 (file)
 // Trace route between two nodes
 //
 
-BOOL TraceRoute(Node *pSrc, Node *pDest, NetObj **ppTrace)
+NETWORK_PATH_TRACE *TraceRoute(Node *pSrc, Node *pDest)
 {
-   DWORD dwNextHop, dwDestAddr;
-   Node *pCurr;
+   DWORD dwNextHop, dwDestAddr, dwIfIndex, dwHopCount;
+   Node *pCurr, *pNext;
+   NETWORK_PATH_TRACE *pTrace;
 
+   pTrace = (NETWORK_PATH_TRACE *)malloc(sizeof(NETWORK_PATH_TRACE));
+   memset(pTrace, 0, sizeof(NETWORK_PATH_TRACE));
+   
    dwDestAddr = pDest->IpAddr();
-   do
+
+   for(pCurr = pSrc, dwHopCount = 0; (pCurr != pDest) && (pCurr != NULL) && (dwHopCount < 30); pCurr = pNext, dwHopCount++)
    {
-      dwNextHop = pCurr->GetNextHop(dwDestAddr);
-      if (dwNextHop != INADDR_NONE)
+      if (pCurr->GetNextHop(dwDestAddr, &dwNextHop, &dwIfIndex))
+      {
+         pNext = FindNodeByIP(dwNextHop);
+         pTrace->pHopList = (HOP_INFO *)realloc(pTrace->pHopList, sizeof(HOP_INFO) * (pTrace->iNumHops + 1));
+         pTrace->pHopList[pTrace->iNumHops].dwNextHop = dwNextHop;
+         pTrace->pHopList[pTrace->iNumHops].dwIfIndex = dwIfIndex;
+         pTrace->pHopList[pTrace->iNumHops].pObject = pCurr;
+         pTrace->iNumHops++;
+         if ((pNext == pCurr) || (dwNextHop == 0))
+            pNext = NULL;     // Directly connected subnet, stop trace
+      }
+      else
       {
-         pCurr = FindNodeByIP(dwNextHop);
+         pNext = NULL;
       }
-   } while((pCurr != pDest) && (dwNextHop != INADDR_NONE));
+   }
+
+   return pTrace;
+}
+
 
-   return FALSE;
+//
+// Destroy trace information
+//
+
+void DestroyTraceData(NETWORK_PATH_TRACE *pTrace)
+{
+   if (pTrace != NULL)
+   {
+      safe_free(pTrace->pHopList);
+      free(pTrace);
+   }
 }
index 3878393..330047f 100644 (file)
@@ -103,6 +103,7 @@ typedef __console_ctx * CONSOLE_CTX;
 #include "messages.h"
 #include "nms_locks.h"
 #include "nms_pkg.h"
+#include "nms_topo.h"
 
 
 //
index 6c1fa41..5272939 100644 (file)
@@ -86,6 +86,9 @@ public:
    void PrepareMessage(NXC_EVENT *pEventData);
 
    char *ExpandText(char *szTemplate);
+
+   char *GetParameter(DWORD dwIndex) { return (dwIndex < m_dwNumParameters) ? m_ppszParameters[dwIndex] : NULL; }
+   DWORD GetParameterAsULong(DWORD dwIndex) { return (dwIndex < m_dwNumParameters) ? strtoul(m_ppszParameters[dwIndex], NULL, 0) : 0; }
 };
 
 
index da0e176..63b1a66 100644 (file)
@@ -43,6 +43,7 @@ class Queue;
 extern DWORD g_dwDiscoveryPollingInterval;
 extern DWORD g_dwStatusPollingInterval;
 extern DWORD g_dwConfigurationPollingInterval;
+extern DWORD g_dwRoutingTableUpdateInterval;
 
 
 //
@@ -93,6 +94,7 @@ extern DWORD g_dwConfigurationPollingInterval;
 #define NDF_QUEUED_FOR_DISCOVERY_POLL  0x0020
 #define NDF_FORCE_STATUS_POLL          0x0040
 #define NDF_FORCE_CONFIGURATION_POLL   0x0080
+#define NDF_QUEUED_FOR_ROUTE_POLL      0x0100
 
 
 //
@@ -367,6 +369,7 @@ protected:
    DWORD m_dwIfType;
    DWORD m_dwIpNetMask;
    BYTE m_bMacAddr[MAC_ADDR_LENGTH];
+   QWORD m_qwLastDownEventId;
 
 public:
    Interface();
@@ -388,6 +391,9 @@ public:
    DWORD IfType(void) { return m_dwIfType; }
    const BYTE *MacAddr(void) { return m_bMacAddr; }
 
+   QWORD GetLastDownEventId(void) { return m_qwLastDownEventId; }
+   void SetLastDownEventId(QWORD qwId) { m_qwLastDownEventId = qwId; }
+
    BOOL IsFake(void) { return (m_dwIfIndex == 1) && 
                               (m_dwIfType == IFTYPE_OTHER) &&
                               (!_tcscmp(m_szName, _T("lan0"))) &&
@@ -464,8 +470,10 @@ protected:
    time_t m_tLastDiscoveryPoll;
    time_t m_tLastStatusPoll;
    time_t m_tLastConfigurationPoll;
+   time_t m_tLastRTUpdate;
    MUTEX m_hPollerMutex;
    MUTEX m_hAgentAccessMutex;
+   MUTEX m_mutexRTAccess;
    AgentConnection *m_pAgentConnection;
    DWORD m_dwPollerNode;      // Node used for network service polling
    QWORD m_qwLastEvents[MAX_LAST_EVENTS];
@@ -477,6 +485,9 @@ protected:
    void AgentLock(void) { MutexLock(m_hAgentAccessMutex, INFINITE); }
    void AgentUnlock(void) { MutexUnlock(m_hAgentAccessMutex); }
 
+   void RTLock(void) { MutexLock(m_mutexRTAccess, INFINITE); }
+   void RTUnlock(void) { MutexUnlock(m_mutexRTAccess); }
+
    void CheckOSPFSupport(void);
 
    DWORD GetInterfaceCount(Interface **ppInterface);
@@ -505,6 +516,8 @@ public:
    BOOL IsRouter(void) { return m_dwFlags & NF_IS_ROUTER ? TRUE : FALSE; }
    BOOL IsLocalManagement(void) { return m_dwFlags & NF_IS_LOCAL_MGMT ? TRUE : FALSE; }
 
+   BOOL IsDown(void) { return m_dwDynamicFlags & NDF_UNREACHEABLE ? TRUE : FALSE; }
+
    const char *ObjectId(void) { return m_szObjectId; }
 
    void AddInterface(Interface *pInterface) { AddChild(pInterface); pInterface->AddParent(this); }
@@ -521,17 +534,21 @@ public:
    int GetInterfaceStatusFromSNMP(DWORD dwIndex);
    int GetInterfaceStatusFromAgent(DWORD dwIndex);
    ROUTING_TABLE *GetRoutingTable(void);
-   DWORD GetNextHop(DWORD dwDestAddr);
+   ROUTING_TABLE *GetCachedRoutingTable(void) { return m_pRoutingTable; }
+   BOOL GetNextHop(DWORD dwDestAddr, DWORD *pdwNextHop, DWORD *pdwIfIndex);
 
    void SetDiscoveryPollTimeStamp(void) { m_tLastDiscoveryPoll = time(NULL); }
    void StatusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller);
    void ConfigurationPoll(ClientSession *pSession, DWORD dwRqId, int nPoller);
+   void UpdateRoutingTable(void);
    BOOL ReadyForStatusPoll(void);
    BOOL ReadyForConfigurationPoll(void);
    BOOL ReadyForDiscoveryPoll(void);
+   BOOL ReadyForRoutePoll(void);
    void LockForStatusPoll(void);
    void LockForConfigurationPoll(void);
    void LockForDiscoveryPoll(void);
+   void LockForRoutePoll(void);
 
    virtual void CalculateCompoundStatus(void);
 
@@ -603,6 +620,14 @@ inline BOOL Node::ReadyForDiscoveryPoll(void)
                ? TRUE : FALSE; 
 }
 
+inline BOOL Node::ReadyForRoutePoll(void) 
+{ 
+   return ((m_iStatus != STATUS_UNMANAGED) &&
+           (!(m_dwDynamicFlags & NDF_QUEUED_FOR_ROUTE_POLL)) &&
+           ((DWORD)time(NULL) - (DWORD)m_tLastRTUpdate > g_dwRoutingTableUpdateInterval))
+               ? TRUE : FALSE; 
+}
+
 inline void Node::LockForStatusPoll(void)
 { 
    LockData(); 
@@ -624,6 +649,13 @@ inline void Node::LockForDiscoveryPoll(void)
    UnlockData(); 
 }
 
+inline void Node::LockForRoutePoll(void) 
+{ 
+   LockData(); 
+   m_dwDynamicFlags |= NDF_QUEUED_FOR_ROUTE_POLL; 
+   UnlockData(); 
+}
+
 
 //
 // Subnet
similarity index 64%
copy from src/server/core/tracert.cpp
copy to src/server/include/nms_topo.h
index d0db790..6f87722 100644 (file)
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 **
-** $module: tracert.cpp
+** $module: nms_topo.h
 **
 **/
 
-#include "nxcore.h"
+#ifndef _nms_topo_h_
+#define _nms_topo_h_
 
 
 //
-// Trace route between two nodes
+// Hop information structure
 //
 
-BOOL TraceRoute(Node *pSrc, Node *pDest, NetObj **ppTrace)
+struct HOP_INFO
 {
-   DWORD dwNextHop, dwDestAddr;
-   Node *pCurr;
-
-   dwDestAddr = pDest->IpAddr();
-   do
-   {
-      dwNextHop = pCurr->GetNextHop(dwDestAddr);
-      if (dwNextHop != INADDR_NONE)
-      {
-         pCurr = FindNodeByIP(dwNextHop);
-      }
-   } while((pCurr != pDest) && (dwNextHop != INADDR_NONE));
-
-   return FALSE;
-}
+   DWORD dwNextHop;
+   NetObj *pObject;
+   DWORD dwIfIndex;
+};
+
+
+//
+// Network path trace
+//
+
+struct NETWORK_PATH_TRACE
+{
+   int iNumHops;
+   HOP_INFO *pHopList;
+};
+
+
+//
+// Topology functions
+//
+
+NETWORK_PATH_TRACE *TraceRoute(Node *pSrc, Node *pDest);
+void DestroyTraceData(NETWORK_PATH_TRACE *pTrace);
+
+
+#endif   /* _nms_topo_h_ */
index 7708683..7f7a57c 100644 (file)
@@ -424,7 +424,7 @@ void AgentConnection::DestroyResultData(void)
 INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
 {
    INTERFACE_LIST *pIfList = NULL;
-   DWORD i;
+   DWORD i, dwBits;
    TCHAR *pChar, *pBuf;
 
    if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
@@ -464,7 +464,8 @@ INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
                pSlash = _T("24");
             }
             pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
-            pIfList->pInterfaces[i].dwIpNetMask = ~(0xFFFFFFFF >> _tcstoul(pSlash, NULL, 10));
+            dwBits = _tcstoul(pSlash, NULL, 10);
+            pIfList->pInterfaces[i].dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
             pBuf = pChar + 1;
          }
 
@@ -1126,7 +1127,7 @@ DWORD AgentConnection::GetConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
 ROUTING_TABLE *AgentConnection::GetRoutingTable(void)
 {
    ROUTING_TABLE *pRT = NULL;
-   DWORD i;
+   DWORD i, dwBits;
    TCHAR *pChar, *pBuf;
 
    if (GetList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
@@ -1157,7 +1158,8 @@ ROUTING_TABLE *AgentConnection::GetRoutingTable(void)
                pSlash = _T("24");
             }
             pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
-            pRT->pRoutes[i].dwDestMask = ~(0xFFFFFFFF >> _tcstoul(pSlash, NULL, 10));
+            dwBits = _tcstoul(pSlash, NULL, 10);
+            pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
             pBuf = pChar + 1;
          }