API for reading FDB
authorVictor Kirhenshtein <victor@netxms.org>
Mon, 21 Jul 2014 12:05:45 +0000 (15:05 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Mon, 21 Jul 2014 12:05:45 +0000 (15:05 +0300)
12 files changed:
include/nxclapi.h
src/java/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/java/netxms-client/src/main/java/org/netxms/client/constants/RCC.java
src/java/netxms-client/src/main/java/org/netxms/client/topology/FdbEntry.java [new file with mode: 0644]
src/java/netxms-client/src/main/resources/messages.properties
src/java/netxms-client/src/main/resources/messages_es.properties
src/java/netxms-client/src/main/resources/messages_ru.properties
src/java/netxms-client/src/test/java/org/netxms/client/TopologyTest.java
src/libnxcl/main.cpp
src/server/core/fdb.cpp
src/server/core/session.cpp
src/server/include/nms_topo.h

index b42d03d..901680b 100644 (file)
@@ -536,6 +536,7 @@ enum
 #define RCC_HDLINK_INTERNAL_ERROR    ((UINT32)111)
 #define RCC_NO_LDAP_CONNECTION       ((UINT32)112)
 #define RCC_NO_ROUTING_TABLE         ((UINT32)113)
+#define RCC_NO_FDB                   ((UINT32)114)
 
 /**
  * Mask bits for NXCModifyEventTemplate()
index 980745a..16c8fa1 100644 (file)
@@ -163,6 +163,7 @@ import org.netxms.client.snmp.SnmpUsmCredential;
 import org.netxms.client.snmp.SnmpValue;
 import org.netxms.client.snmp.SnmpWalkListener;
 import org.netxms.client.topology.ConnectionPoint;
+import org.netxms.client.topology.FdbEntry;
 import org.netxms.client.topology.NetworkPath;
 import org.netxms.client.topology.Route;
 import org.netxms.client.topology.VlanInfo;
@@ -6777,10 +6778,10 @@ public class NXCSession implements Session, ScriptLibraryManager, UserManager, S
    /**
     * Get routing table from node
     * 
-    * @param nodeId
-    * @return
-    * @throws IOException
-    * @throws NXCException
+    * @param nodeId node object ID
+    * @return list of routing table entries
+    * @throws IOException  if socket or file I/O error occurs
+    * @throws NXCException if NetXMS server returns an error or operation was timed out
     */
    public List<Route> getRoutingTable(long nodeId) throws IOException, NXCException
    {
@@ -6799,6 +6800,31 @@ public class NXCSession implements Session, ScriptLibraryManager, UserManager, S
       return rt;
    }
 
+   /**
+    * Get switch forwarding database (MAC address table) from node
+    * 
+    * @param nodeId node object ID
+    * @return list of switch forwarding database entries
+    * @throws IOException  if socket or file I/O error occurs
+    * @throws NXCException if NetXMS server returns an error or operation was timed out
+    */
+   public List<FdbEntry> getSwitchForwardingDatabase(long nodeId) throws IOException, NXCException
+   {
+      final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SWITCH_FDB);
+      msg.setVariableInt32(NXCPCodes.VID_OBJECT_ID, (int) nodeId);
+      sendMessage(msg);
+      final NXCPMessage response = waitForRCC(msg.getMessageId());
+      int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ELEMENTS);
+      List<FdbEntry> fdb = new ArrayList<FdbEntry>(count);
+      long varId = NXCPCodes.VID_ELEMENT_LIST_BASE;
+      for(int i = 0; i < count; i++)
+      {
+         fdb.add(new FdbEntry(response, varId));
+         varId += 10;
+      }
+      return fdb;
+   }
+
    /**
     * Get list of wireless stations registered at given wireless controller.
     *
index 1aabd62..8f98c91 100644 (file)
@@ -102,6 +102,7 @@ public final class RCC extends CommonRCC
    public static final int HDLINK_INTERNAL_ERROR = 111;
    public static final int NO_LDAP_CONNECTION = 112;
    public static final int NO_ROUTING_TABLE = 113;
+   public static final int NO_FDB = 114;
        
        // SNMP-specific, has no corresponding RCC_xxx constants in C library
        public static final int BAD_MIB_FILE_HEADER = 1001;
diff --git a/src/java/netxms-client/src/main/java/org/netxms/client/topology/FdbEntry.java b/src/java/netxms-client/src/main/java/org/netxms/client/topology/FdbEntry.java
new file mode 100644 (file)
index 0000000..5019c0f
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * NetXMS - open source network management system
+ * Copyright (C) 2003-2014 Victor Kirhenshtein
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.netxms.client.topology;
+
+import org.netxms.base.NXCPMessage;
+import org.netxms.client.MacAddress;
+
+/**
+ * Switch forwarding database entry
+ */
+public class FdbEntry
+{
+   private MacAddress address;
+   private int interfaceIndex;
+   private int port;
+   private long nodeId;
+   private int vlanId;
+   private int type;
+   
+   /**
+    * Create FDB entry from NXCP message.
+    * 
+    * @param msg
+    * @param baseId
+    */
+   public FdbEntry(NXCPMessage msg, long baseId)
+   {
+      address = new MacAddress(msg.getVariableAsBinary(baseId));
+      interfaceIndex = msg.getVariableAsInteger(baseId + 1);
+      port = msg.getVariableAsInteger(baseId + 2);
+      nodeId = msg.getVariableAsInt64(baseId + 3);
+      vlanId = msg.getVariableAsInteger(baseId + 4);
+      type = msg.getVariableAsInteger(baseId + 5);
+   }
+
+   /**
+    * @return the address
+    */
+   public MacAddress getAddress()
+   {
+      return address;
+   }
+
+   /**
+    * @return the interfaceIndex
+    */
+   public int getInterfaceIndex()
+   {
+      return interfaceIndex;
+   }
+
+   /**
+    * @return the port
+    */
+   public int getPort()
+   {
+      return port;
+   }
+
+   /**
+    * @return the nodeId
+    */
+   public long getNodeId()
+   {
+      return nodeId;
+   }
+
+   /**
+    * @return the vlanId
+    */
+   public int getVlanId()
+   {
+      return vlanId;
+   }
+
+   /**
+    * @return the type
+    */
+   public int getType()
+   {
+      return type;
+   }
+
+   /* (non-Javadoc)
+    * @see java.lang.Object#toString()
+    */
+   @Override
+   public String toString()
+   {
+      return "FdbEntry [address=" + address + ", interfaceIndex=" + interfaceIndex + ", port=" + port + ", nodeId=" + nodeId
+            + ", vlanId=" + vlanId + ", type=" + type + "]";
+   }
+}
index 2e569e9..81d108f 100644 (file)
@@ -112,6 +112,7 @@ RCC_0110 = Helpdesk link access denied
 RCC_0111 = Helpdesk link internal error
 RCC_0112 = LDAP connection error
 RCC_0113 = Routing table unavailable
+RCC_0114 = Switch forwading database unavailable
 RCC_1001 = Bad MIB file header
 RCC_1002 = Bad MIB file data
 RCC_UNKNOWN = Error %d
index 53f786f..bc8ddc5 100644 (file)
@@ -112,6 +112,7 @@ RCC_0110 = Helpdesk link access denied
 RCC_0111 = Helpdesk link internal error
 RCC_0112 = LDAP connection error
 RCC_0113 = Routing table unavailable
+RCC_0114 = Switch forwading database unavailable
 RCC_1001 = Error en la cabecera del fichero MIB
 RCC_1002 = Error en los datos del fichero MIB
 RCC_UNKNOWN = Error %d
index 32ea154..1dfc5d2 100644 (file)
@@ -112,6 +112,7 @@ RCC_0110 = \u041e\u0442\u043a\u0430\u0437 \u0432 \u0434\u043e\u0441\u0442\u0443\
 RCC_0111 = \u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0438 \u0441\u043e \u0441\u043b\u0443\u0436\u0431\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438
 RCC_0112 = \u041d\u0435\u0442 \u0441\u0432\u044f\u0437\u0438 \u0441 LDAP \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c
 RCC_0113 = \u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430
+RCC_0114 = \u0422\u0430\u0431\u043b\u0438\u0446\u0430 MAC \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430
 RCC_1001 = \u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0444\u0430\u0439\u043b\u0430 MIB
 RCC_1002 = \u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 MIB
 RCC_UNKNOWN = \u041e\u0448\u0438\u0431\u043a\u0430 %d
index 58d4ce1..f1c3313 100644 (file)
@@ -22,6 +22,7 @@ import java.util.List;
 import org.netxms.client.maps.NetworkMapLink;
 import org.netxms.client.maps.NetworkMapPage;
 import org.netxms.client.maps.elements.NetworkMapElement;
+import org.netxms.client.topology.FdbEntry;
 import org.netxms.client.topology.Route;
 
 
@@ -67,4 +68,15 @@ public class TopologyTest extends SessionTest
       
       session.disconnect();
    }
+
+   public void testSwitchForwardingTable() throws Exception
+   {
+      final NXCSession session = connect();
+
+      List<FdbEntry> fdb = session.getSwitchForwardingDatabase(NODE_ID);
+      for(FdbEntry e : fdb)
+         System.out.println(e.toString());
+      
+      session.disconnect();
+   }
 }
index d8a672b..c577d1c 100644 (file)
@@ -389,9 +389,10 @@ const TCHAR LIBNXCL_EXPORTABLE *NXCGetErrorText(UINT32 dwError)
       _T("Helpdesk link access denied"),
       _T("Helpdesk link internal error"),
       _T("LDAP connection error"),
-      _T("Routing table unavailable")
+      _T("Routing table unavailable"),
+      _T("Switch forwarding database unavailable")
    };
-       return (dwError <= RCC_NO_ROUTING_TABLE) ? pszErrorText[dwError] : _T("No text message for this error");
+       return (dwError <= RCC_NO_FDB) ? pszErrorText[dwError] : _T("No text message for this error");
 }
 
 #if defined(_WIN32) && !defined(UNDER_CE)
index 574b0bc..d91c927 100644 (file)
@@ -170,6 +170,25 @@ void ForwardingDatabase::print(CONSOLE_CTX ctx, Node *owner)
    ConsolePrintf(ctx, _T("\n%d entries\n\n"), m_fdbSize);
 }
 
+/**
+ * Fill NXCP message with FDB data
+ */
+void ForwardingDatabase::fillMessage(CSCPMessage *msg)
+{
+   msg->SetVariable(VID_NUM_ELEMENTS, (UINT32)m_fdbSize);
+   UINT32 fieldId = VID_ELEMENT_LIST_BASE;
+       for(int i = 0; i < m_fdbSize; i++)
+   {
+      msg->SetVariable(fieldId++, m_fdb[i].macAddr, MAC_ADDR_LENGTH);
+      msg->SetVariable(fieldId++, m_fdb[i].ifIndex);
+      msg->SetVariable(fieldId++, m_fdb[i].port);
+      msg->SetVariable(fieldId++, m_fdb[i].nodeObject);
+      msg->SetVariable(fieldId++, m_fdb[i].vlanId);
+      msg->SetVariable(fieldId++, m_fdb[i].type);
+      fieldId += 4;
+   }
+}
+
 /**
  * Sort FDB
  */
@@ -209,7 +228,7 @@ static UINT32 FDBHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Transport *
       {
          int port = varPort->getValueAsInt();
          int status = varStatus->getValueAsInt();
-         if ((port > 0) && (status == 3))              // status 3 == learned
+         if ((port > 0) && (status == 3))  // status: 3 == learned
          {
             FDB_ENTRY entry;
 
@@ -218,6 +237,8 @@ static UINT32 FDBHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Transport *
             pVar->getRawValue(entry.macAddr, MAC_ADDR_LENGTH);
             Node *node = FindNodeByMAC(entry.macAddr);
             entry.nodeObject = (node != NULL) ? node->Id() : 0;
+            entry.vlanId = ((ForwardingDatabase *)arg)->getCurrentVlanId();
+            entry.type = (UINT16)status;
             ((ForwardingDatabase *)arg)->addEntry(&entry);
          }
       }
@@ -254,7 +275,7 @@ static UINT32 Dot1qTpFdbHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Tran
        if (rcc == SNMP_ERR_SUCCESS)
    {
                int status = pRespPDU->getVariable(0)->getValueAsInt();
-               if (status == 3)        // status 3 == learned
+               if (status == 3) // status: 3 == learned
                {
                        FDB_ENTRY entry;
 
@@ -264,6 +285,8 @@ static UINT32 Dot1qTpFdbHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Tran
                                entry.macAddr[j++] = (BYTE)oid[i];
                        Node *node = FindNodeByMAC(entry.macAddr);
                        entry.nodeObject = (node != NULL) ? node->Id() : 0;
+         entry.vlanId = (UINT16)oid[oidLen - MAC_ADDR_LENGTH - 1];
+         entry.type = (UINT16)status;
                        ((ForwardingDatabase *)arg)->addEntry(&entry);
                }
       delete pRespPDU;
@@ -299,6 +322,7 @@ ForwardingDatabase *GetSwitchForwardingDatabase(Node *node)
        int size = fdb->getSize();
        DbgPrintf(5, _T("FDB: %d entries read from dot1qTpFdbTable"), size);
 
+   fdb->setCurrentVlanId(1);
        node->callSnmpEnumerate(_T(".1.3.6.1.2.1.17.4.3.1.1"), FDBHandler, fdb);
        DbgPrintf(5, _T("FDB: %d entries read from dot1dTpFdbTable"), fdb->getSize() - size);
        size = fdb->getSize();
@@ -312,6 +336,7 @@ ForwardingDatabase *GetSwitchForwardingDatabase(Node *node)
                        {
                                TCHAR context[16];
                                _sntprintf(context, 16, _T("%s%d"), (node->getSNMPVersion() < SNMP_VERSION_3) ? _T("") : _T("vlan-"), vlans->get(i)->getVlanId());
+            fdb->setCurrentVlanId((UINT16)vlans->get(i)->getVlanId());
                                node->callSnmpEnumerate(_T(".1.3.6.1.2.1.17.4.3.1.1"), FDBHandler, fdb, context);
                                DbgPrintf(5, _T("FDB: %d entries read from dot1dTpFdbTable in context %s"), fdb->getSize() - size, context);
                                size = fdb->getSize();
index 07f2405..492a66c 100644 (file)
@@ -13273,6 +13273,17 @@ void ClientSession::getSwitchForwardingDatabase(CSCPMessage *request)
    {
       if (node->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
       {
+         ForwardingDatabase *fdb = node->getSwitchForwardingDatabase();
+         if (fdb != NULL)
+         {
+            msg.SetVariable(VID_RCC, RCC_SUCCESS);
+            fdb->fillMessage(&msg);
+                       fdb->decRefCount();
+         }
+         else
+         {
+            msg.SetVariable(VID_RCC, RCC_NO_FDB);
+         }
       }
       else
       {
@@ -13321,6 +13332,7 @@ void ClientSession::getRoutingTable(CSCPMessage *request)
                msg.SetVariable(id++, rt->pRoutes[i].dwRouteType);
                id += 5;
             }
+                       DestroyRoutingTable(rt);
          }
          else
          {
index 47226ae..dd90935 100644 (file)
@@ -87,6 +87,8 @@ struct FDB_ENTRY
        UINT32 ifIndex;                 // Interface index
        BYTE macAddr[MAC_ADDR_LENGTH]; // MAC address
        UINT32 nodeObject;              // ID of node object or 0 if not found
+   UINT16 vlanId;
+   UINT16 type;
 };
 
 /**
@@ -111,6 +113,7 @@ private:
        int m_pmAllocated;
        PORT_MAPPING_ENTRY *m_portMap;
        time_t m_timestamp;
+   UINT16 m_currentVlanId;
 
        UINT32 ifIndexFromPort(UINT32 port);
 
@@ -127,11 +130,15 @@ public:
        int getSize() { return m_fdbSize; }
        FDB_ENTRY *getEntry(int index) { return ((index >= 0) && (index < m_fdbSize)) ? &m_fdb[index] : NULL; }
 
+   void setCurrentVlanId(UINT16 vlanId) { m_currentVlanId = vlanId; }
+   UINT16 getCurrentVlanId() { return m_currentVlanId; }
+
        UINT32 findMacAddress(const BYTE *macAddr);
        bool isSingleMacOnPort(UINT32 ifIndex, BYTE *macAddr = NULL);
        int getMacCountOnPort(UINT32 ifIndex);
 
    void print(CONSOLE_CTX ctx, Node *owner);
+   void fillMessage(CSCPMessage *msg);
 };
 
 /**