initial support for sub-interfaces; Juniper driver reports logical interfaces on...
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 18 Jun 2017 20:52:35 +0000 (23:52 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 18 Jun 2017 20:52:35 +0000 (23:52 +0300)
14 files changed:
include/netxmsdb.h
include/nms_cscp.h
sql/schema.in
src/java/client/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/java/client/netxms-client/src/main/java/org/netxms/client/objects/Interface.java
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/GeneralInfo.java
src/server/core/interface.cpp
src/server/core/node.cpp
src/server/drivers/juniper/juniper.cpp
src/server/include/nms_objects.h
src/server/include/nxsrvapi.h
src/server/libnxsrv/iflist.cpp
src/server/tools/nxdbmgr/upgrade.cpp
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/GeneralInfo.java

index 4ec09c6..ef9ffe0 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION   454
+#define DB_FORMAT_VERSION   455
 
 #endif
index 7d5da94..a9feefc 100644 (file)
@@ -1180,6 +1180,7 @@ typedef struct
 #define VID_TUNNEL_GUID             ((UINT32)577)
 #define VID_ORGANIZATION            ((UINT32)578)
 #define VID_TUNNEL_ID               ((UINT32)579)
+#define VID_PARENT_INTERFACE        ((UINT32)580)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
index f6c46c8..a65e150 100644 (file)
@@ -402,6 +402,7 @@ CREATE TABLE interfaces
 (
   id integer not null,
   node_id integer not null,
+  parent_iface integer not null,
   flags integer not null,
   if_type integer not null,
   if_index integer not null,
index 2e515b6..8b6194e 100644 (file)
@@ -966,6 +966,7 @@ public class NXCPCodes
    public static final long VID_TUNNEL_GUID = 577;
    public static final long VID_ORGANIZATION = 578;
    public static final long VID_TUNNEL_ID = 579;
+   public static final long VID_PARENT_INTERFACE = 580;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
index 98bf219..476c627 100644 (file)
@@ -415,6 +415,7 @@ public class Interface extends GenericObject
        private int dot1xPaeState;
        private int dot1xBackendState;
        private SnmpObjectId ifTableSuffix;
+   private long parentInterfaceId;
        
        /**
         * @param msg
@@ -443,6 +444,7 @@ public class Interface extends GenericObject
                dot1xPaeState = msg.getFieldAsInt32(NXCPCodes.VID_DOT1X_PAE_STATE);
                dot1xBackendState = msg.getFieldAsInt32(NXCPCodes.VID_DOT1X_BACKEND_STATE);
                ifTableSuffix = new SnmpObjectId(msg.getFieldAsUInt32Array(NXCPCodes.VID_IFTABLE_SUFFIX));
+               parentInterfaceId = msg.getFieldAsInt64(NXCPCodes.VID_PARENT_INTERFACE);
                
                int count = msg.getFieldAsInt32(NXCPCodes.VID_IP_ADDRESS_COUNT);
                ipAddressList = new ArrayList<InetAddressEx>(count);
@@ -845,6 +847,25 @@ public class Interface extends GenericObject
       return ifTypeNames.get(ifType);
    }
 
+   /**
+    * Get object ID of parent interface
+    * 
+    * @return parent interface object ID or 0
+    */
+   public long getParentInterfaceId()
+   {
+      return parentInterfaceId;
+   }
+   
+   /**
+    * Get parent interface object
+    * 
+    * @return parent interface object or null
+    */
+   public Interface getParentInterface()
+   {
+      return session.findObjectById(parentInterfaceId, Interface.class);
+   }
 
    /* (non-Javadoc)
     * @see org.netxms.client.objects.AbstractObject#getStrings()
index ffe71ee..cbf1fba 100644 (file)
@@ -101,6 +101,9 @@ public class GeneralInfo extends TableElement
             break;
                        case AbstractObject.OBJECT_INTERFACE:
                                Interface iface = (Interface)object;
+                               Interface parentIface = iface.getParentInterface();
+                               if (parentIface != null)
+                   addPair("Parent interface", parentIface.getObjectName());
                                addPair(Messages.get().GeneralInfo_IfIndex, Integer.toString(iface.getIfIndex()));
                                String typeName = iface.getIfTypeName();
                                addPair(Messages.get().GeneralInfo_IfType, (typeName != null) ? String.format("%d (%s)", iface.getIfType(), typeName) : Integer.toString(iface.getIfType())); //$NON-NLS-1$
index c6f9a67..fe1acea 100644 (file)
@@ -28,6 +28,7 @@
  */
 Interface::Interface() : NetObj()
 {
+   m_parentInterfaceId = 0;
        m_flags = 0;
        nx_strncpy(m_description, m_name, MAX_DB_STRING);
    m_alias[0] = 0;
@@ -65,6 +66,7 @@ Interface::Interface() : NetObj()
  */
 Interface::Interface(const InetAddressList& addrList, UINT32 zoneId, bool bSyntheticMask) : NetObj()
 {
+   m_parentInterfaceId = 0;
        m_flags = bSyntheticMask ? IF_SYNTHETIC_MASK : 0;
    if (addrList.isLoopbackOnly())
                m_flags |= IF_LOOPBACK;
@@ -114,6 +116,7 @@ Interface::Interface(const TCHAR *name, const TCHAR *descr, UINT32 index, const
        else
                m_flags = 0;
 
+   m_parentInterfaceId = 0;
    nx_strncpy(m_name, name, MAX_OBJECT_NAME);
    nx_strncpy(m_description, descr, MAX_DB_STRING);
    m_alias[0] = 0;
@@ -153,7 +156,7 @@ Interface::Interface(const TCHAR *name, const TCHAR *descr, UINT32 index, const
  */
 Interface::~Interface()
 {
-   safe_free(m_ifTableSuffix);
+   free(m_ifTableSuffix);
 }
 
 /**
@@ -186,7 +189,8 @@ bool Interface::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
                _T("mac_addr,flags,required_polls,bridge_port,phy_slot,")
                _T("phy_port,peer_node_id,peer_if_id,description,")
                _T("dot1x_pae_state,dot1x_backend_state,admin_state,")
-      _T("oper_state,peer_proto,alias,mtu,speed,iftable_suffix FROM interfaces WHERE id=?"));
+      _T("oper_state,peer_proto,alias,mtu,speed,parent_iface,")
+      _T("iftable_suffix FROM interfaces WHERE id=?"));
        if (hStmt == NULL)
                return false;
        DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
@@ -221,9 +225,10 @@ bool Interface::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
                DBGetField(hResult, 0, 17, m_alias, MAX_DB_STRING);
                m_mtu = DBGetFieldULong(hResult, 0, 18);
       m_speed = DBGetFieldUInt64(hResult, 0, 19);
+      m_parentInterfaceId = DBGetFieldULong(hResult, 0, 20);
 
       TCHAR suffixText[128];
-      DBGetField(hResult, 0, 20, suffixText, 128);
+      DBGetField(hResult, 0, 21, suffixText, 128);
       StrStrip(suffixText);
       if (suffixText[0] == 0)
       {
@@ -347,15 +352,17 @@ BOOL Interface::saveToDatabase(DB_HANDLE hdb)
                        _T("required_polls=?,bridge_port=?,phy_slot=?,phy_port=?,")
                        _T("peer_node_id=?,peer_if_id=?,description=?,admin_state=?,")
                        _T("oper_state=?,dot1x_pae_state=?,dot1x_backend_state=?,")
-         _T("peer_proto=?,alias=?,mtu=?,speed=?,iftable_suffix=? WHERE id=?"));
+         _T("peer_proto=?,alias=?,mtu=?,speed=?,parent_iface=?,")
+         _T("iftable_suffix=? WHERE id=?"));
        }
    else
        {
                hStmt = DBPrepare(hdb,
                        _T("INSERT INTO interfaces (node_id,if_type,if_index,mac_addr,")
                        _T("flags,required_polls,bridge_port,phy_slot,phy_port,peer_node_id,peer_if_id,description,")
-         _T("admin_state,oper_state,dot1x_pae_state,dot1x_backend_state,peer_proto,alias,mtu,speed,iftable_suffix,id) ")
-                       _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+         _T("admin_state,oper_state,dot1x_pae_state,dot1x_backend_state,peer_proto,alias,mtu,speed,")
+         _T("parent_iface,iftable_suffix,id) ")
+                       _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
        }
        if (hStmt == NULL)
        {
@@ -383,16 +390,17 @@ BOOL Interface::saveToDatabase(DB_HANDLE hdb)
        DBBind(hStmt, 18, DB_SQLTYPE_VARCHAR, m_alias, DB_BIND_STATIC);
        DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_mtu);
        DBBind(hStmt, 20, DB_SQLTYPE_BIGINT, m_speed);
+   DBBind(hStmt, 21, DB_SQLTYPE_INTEGER, m_parentInterfaceId);
    if (m_ifTableSuffixLen > 0)
    {
       TCHAR buffer[128];
-      DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, SNMPConvertOIDToText(m_ifTableSuffixLen, m_ifTableSuffix, buffer, 128), DB_BIND_TRANSIENT);
+      DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, SNMPConvertOIDToText(m_ifTableSuffixLen, m_ifTableSuffix, buffer, 128), DB_BIND_TRANSIENT);
    }
    else
    {
-          DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, NULL, DB_BIND_STATIC);
+          DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, NULL, DB_BIND_STATIC);
    }
-       DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_id);
+       DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, m_id);
 
        BOOL success = DBExecute(hStmt);
        DBFreeStatement(hStmt);
@@ -1019,6 +1027,7 @@ void Interface::fillMessageInternal(NXCPMessage *pMsg)
        pMsg->setField(VID_DOT1X_BACKEND_STATE, m_dot1xBackendAuthState);
        pMsg->setField(VID_ZONE_ID, m_zoneId);
    pMsg->setFieldFromInt32Array(VID_IFTABLE_SUFFIX, m_ifTableSuffixLen, m_ifTableSuffix);
+   pMsg->setField(VID_PARENT_INTERFACE, m_parentInterfaceId);
 }
 
 /**
index 4548612..5140fd2 100644 (file)
@@ -1055,10 +1055,14 @@ bool Node::filterInterface(InterfaceInfo *info)
 
    Interface *iface;
    if (info->name[0] != 0)
+   {
       iface = new Interface(info->name, (info->description[0] != 0) ? info->description : info->name,
                                  info->index, info->ipAddrList, info->type, m_zoneId);
+   }
    else
+   {
       iface = new Interface(info->ipAddrList, m_zoneId, false);
+   }
    iface->setMacAddr(info->macAddr, false);
    iface->setBridgePortNumber(info->bridgePort);
    iface->setSlotNumber(info->slot);
@@ -3347,6 +3351,26 @@ bool Node::updateInterfaceConfiguration(UINT32 rqid, int maskBits)
             }
          }
       }
+
+      // Set parent interfaces
+      for(int j = 0; j < pIfList->size(); j++)
+      {
+         InterfaceInfo *ifInfo = pIfList->get(j);
+         if (ifInfo->parentIndex != 0)
+         {
+            Interface *parent = findInterfaceByIndex(ifInfo->parentIndex);
+            if (parent != NULL)
+            {
+               Interface *iface = findInterfaceByIndex(ifInfo->index);
+               if (iface != NULL)
+               {
+                  iface->setParentInterface(parent->getId());
+                  nxlog_debug(6, _T("Node::updateInterfaceConfiguration(%s [%u]): set sub-interface: %s [%d] -> %s [%d]"),
+                           m_name, m_id, parent->getName(), parent->getId(), iface->getName(), iface->getId());
+               }
+            }
+         }
+      }
    }
    else if (!(m_flags & NF_REMOTE_AGENT))    /* pIfList == NULL */
    {
@@ -3354,7 +3378,7 @@ bool Node::updateInterfaceConfiguration(UINT32 rqid, int maskBits)
       UINT32 dwCount;
 
       sendPollerMsg(rqid, POLLER_ERROR _T("Unable to get interface list from node\r\n"));
-      DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): Unable to get interface list from node"), m_name, m_id);
+      nxlog_debug(6, _T("Node::updateInterfaceConfiguration(%s [%u]): Unable to get interface list from node"), m_name, m_id);
 
       // Delete all existing interfaces in case of forced capability recheck
       if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
index 0fbf9a3..9461bd0 100644 (file)
@@ -86,6 +86,7 @@ InterfaceList *JuniperDriver::getInterfaces(SNMP_Transport *snmp, StringMap *att
        SNMP_Snapshot *chassisTable = SNMP_Snapshot::create(snmp, _T(".1.3.6.1.4.1.2636.3.3.2.1"));
        if (chassisTable != NULL)
        {
+          // Update slot/port for physical interfaces
       for(int i = 0; i < ifList->size(); i++)
       {
          InterfaceInfo *iface = ifList->get(i);
@@ -109,6 +110,32 @@ InterfaceList *JuniperDriver::getInterfaces(SNMP_Transport *snmp, StringMap *att
          iface->slot = slot - 1;  // Juniper numbers slots from 0 but reports in SNMP as n + 1
          iface->port = port - 1;  // Juniper numbers ports from 0 but reports in SNMP as n + 1
       }
+
+      // Attach logical interfaces to physical
+      for(int i = 0; i < ifList->size(); i++)
+      {
+         InterfaceInfo *iface = ifList->get(i);
+         if (iface->type != IFTYPE_PROP_VIRTUAL)
+            continue;
+
+         SNMP_ObjectId oid = SNMP_ObjectId::parse(_T(".1.3.6.1.4.1.2636.3.3.2.1.1"));
+         oid.extend(iface->index);
+         int slot = chassisTable->getAsInt32(oid);
+
+         oid.changeElement(oid.length() - 2, 2);
+         int pic = chassisTable->getAsInt32(oid);
+
+         oid.changeElement(oid.length() - 2, 3);
+         int port = chassisTable->getAsInt32(oid);
+
+         if ((slot == 0) || (pic != 1) || (port == 0))   // FIXME: support for multiple PICs in one slot
+            continue;
+
+         InterfaceInfo *parent = ifList->findByPhyPosition(slot - 1, port - 1);
+         if (parent != NULL)
+            iface->parentIndex = parent->index;
+      }
+
       delete chassisTable;
        }
        return ifList;
index f951e4e..0e8381f 100644 (file)
@@ -828,6 +828,7 @@ class Cluster;
 class NXCORE_EXPORTABLE Interface : public NetObj
 {
 protected:
+   UINT32 m_parentInterfaceId;
    UINT32 m_index;
    BYTE m_macAddr[MAC_ADDR_LENGTH];
    InetAddressList m_ipAddressList;
@@ -888,6 +889,7 @@ public:
 
    Node *getParentNode();
    UINT32 getParentNodeId();
+   UINT32 getParentInterfaceId() const { return m_parentInterfaceId; }
 
    const InetAddressList *getIpAddressList() { return &m_ipAddressList; }
    const InetAddress& getFirstIpAddress();
@@ -923,6 +925,7 @@ public:
    bool isFake() const { return (m_index == 1) &&
                                 (m_type == IFTYPE_OTHER) &&
                                 !_tcscmp(m_name, _T("unknown")); }
+   bool isSubInterface() const { return m_parentInterfaceId != 0; }
 
    UINT64 getLastDownEventId() const { return m_lastDownEventId; }
    void setLastDownEventId(UINT64 id) { m_lastDownEventId = id; }
@@ -944,6 +947,7 @@ public:
        void setMTU(int mtu) { m_mtu = mtu; setModified(); }
        void setSpeed(UINT64 speed) { m_speed = speed; setModified(); }
    void setIfTableSuffix(int len, const UINT32 *suffix) { lockProperties(); safe_free(m_ifTableSuffix); m_ifTableSuffixLen = len; m_ifTableSuffix = (len > 0) ? (UINT32 *)nx_memdup(suffix, len * sizeof(UINT32)) : NULL; setModified(); unlockProperties(); }
+   void setParentInterface(UINT32 parentInterfaceId) { m_parentInterfaceId = parentInterfaceId; setModified(); }
 
        void updateZoneId();
 
index 367c15d..79b3d93 100644 (file)
@@ -213,6 +213,7 @@ private:
       memset(macAddr, 0, sizeof(macAddr));
       isPhysicalPort = false;
       isSystem = false;
+      parentIndex = 0;
    }
 
 public:
@@ -232,6 +233,7 @@ public:
    bool isSystem;
    UINT32 ifTableSuffix[16];   // actual ifTable suffix
    int ifTableSuffixLength;
+   UINT32 parentIndex;
 
    InterfaceInfo(UINT32 ifIndex)
    {
@@ -271,6 +273,7 @@ public:
        int size() { return m_interfaces->size(); }
        InterfaceInfo *get(int index) { return m_interfaces->get(index); }
        InterfaceInfo *findByIfIndex(UINT32 ifIndex);
+   InterfaceInfo *findByPhyPosition(int slot, int port);
 
        void setData(void *data) { m_data = data; }
        void *getData() { return m_data; }
index 8a2e025..d5b906b 100644 (file)
@@ -45,9 +45,22 @@ InterfaceList::~InterfaceList()
  */
 InterfaceInfo *InterfaceList::findByIfIndex(UINT32 ifIndex)
 {
-   // Delete loopback interface(s) from list
    for(int i = 0; i < m_interfaces->size(); i++)
       if (m_interfaces->get(i)->index == ifIndex)
                        return m_interfaces->get(i);
        return NULL;
 }
+
+/**
+ * Find interface entry by physical position
+ */
+InterfaceInfo *InterfaceList::findByPhyPosition(int slot, int port)
+{
+   for(int i = 0; i < m_interfaces->size(); i++)
+   {
+      InterfaceInfo *iface = m_interfaces->get(i);
+      if (iface->isPhysicalPort && (iface->slot == slot) && (iface->port == port))
+         return iface;
+   }
+   return NULL;
+}
index 1ee997d..15b0d2c 100644 (file)
@@ -746,6 +746,21 @@ static bool SetSchemaVersion(int version)
    return SQLQuery(query);
 }
 
+/**
+ * Upgrade from V454 to V455
+ */
+static BOOL H_UpgradeFromV454(int currVersion, int newVersion)
+{
+   static const TCHAR *batch =
+            _T("ALTER TABLE interfaces ADD parent_iface integer\n")
+            _T("UPDATE interfaces SET parent_iface=0\n")
+            _T("<END>");
+   CHK_EXEC(SQLBatch(batch));
+   CHK_EXEC(SetNotNullConstraint(_T("interfaces"), _T("parent_iface")));
+   CHK_EXEC(SetSchemaVersion(455));
+   return TRUE;
+}
+
 /**
  * Upgrade from V453 to V454
  */
@@ -11954,6 +11969,7 @@ static struct
    { 451, 452, H_UpgradeFromV451 },
    { 452, 453, H_UpgradeFromV452 },
    { 453, 454, H_UpgradeFromV453 },
+   { 454, 455, H_UpgradeFromV454 },
    { 0, 0, NULL }
 };
 
index fdd7961..95c2b33 100644 (file)
@@ -101,6 +101,9 @@ public class GeneralInfo extends TableElement
             break;
                        case AbstractObject.OBJECT_INTERFACE:
                                Interface iface = (Interface)object;
+                               Interface parentIface = iface.getParentInterface();
+                               if (parentIface != null)
+                   addPair("Parent interface", parentIface.getObjectName());
                                addPair(Messages.get().GeneralInfo_IfIndex, Integer.toString(iface.getIfIndex()));
                                String typeName = iface.getIfTypeName();
                                addPair(Messages.get().GeneralInfo_IfType, (typeName != null) ? String.format("%d (%s)", iface.getIfType(), typeName) : Integer.toString(iface.getIfType())); //$NON-NLS-1$