"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/agent/subagents/aix/net.cpp" (23 Feb 2021, 10440 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "net.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2 ** NetXMS subagent for AIX
    3 ** Copyright (C) 2004-2020 Victor Kirhenshtein
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License as published by
    7 ** the Free Software Foundation; either version 2 of the License, or
    8 ** (at your option) any later version.
    9 **
   10 ** This program is distributed in the hope that it will be useful,
   11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 ** GNU General Public License for more details.
   14 **
   15 ** You should have received a copy of the GNU General Public License
   16 ** along with this program; if not, write to the Free Software
   17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18 **
   19 ** File: net.cpp
   20 **
   21 **/
   22 
   23 #include "aix_subagent.h"
   24 #include <sys/ioctl.h>
   25 #include <sys/socket.h>
   26 #include <net/if.h>
   27 #include <sys/ndd.h>
   28 #include <sys/kinfo.h>
   29 
   30 /**
   31  * Function getkerninfo() has not documented, but used in IBM examples.
   32  * It also doesn't have prototype in headers, so we declare it here.
   33  */
   34 #if !HAVE_DECL_GETKERNINFO
   35 extern "C" int getkerninfo(int, void *, void *, void *);
   36 #endif
   37 
   38 /**
   39  * Internal interface info structure
   40  */
   41 typedef struct
   42 {
   43     char name[IFNAMSIZ];
   44     BYTE mac[6];
   45     DWORD ip;
   46     DWORD netmask;
   47     DWORD iftype;
   48 } IF_INFO;
   49 
   50 /**
   51  * Interface data
   52  */
   53 static perfstat_netinterface_t *s_ifaceData = NULL;
   54 static int s_ifaceDataSize = 0;
   55 static time_t s_ifaceDataTimestamp = 0;
   56 static Mutex s_ifaceDataLock;
   57 
   58 /**
   59  * Clear network data
   60  */
   61 void ClearNetworkData()
   62 {
   63     s_ifaceDataLock.lock();
   64    free(s_ifaceData);
   65    s_ifaceData = 0;
   66    s_ifaceDataSize = 0;
   67    s_ifaceDataTimestamp = 0;
   68     s_ifaceDataLock.unlock();
   69 }
   70 
   71 /**
   72  * Get data for all interfaces via libperfstat
   73  */
   74 static bool GetInterfaceData()
   75 {
   76     int ifCount = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0);
   77     if (ifCount < 1)
   78         return false;
   79 
   80     if (ifCount != s_ifaceDataSize)
   81     {
   82         s_ifaceDataSize = ifCount;
   83         s_ifaceData = (perfstat_netinterface_t *)realloc(s_ifaceData, sizeof(perfstat_netinterface_t) * ifCount);
   84     }
   85 
   86     perfstat_id_t firstIface;
   87     strcpy(firstIface.name, FIRST_NETINTERFACE);
   88     bool success = perfstat_netinterface(&firstIface, s_ifaceData, sizeof(perfstat_netinterface_t), ifCount) > 0;
   89     if (success)
   90         s_ifaceDataTimestamp = time(NULL);
   91     return success;
   92 }
   93 
   94 /**
   95  * Get interface data
   96  */
   97 LONG H_NetInterfaceInfo(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
   98 {
   99     char ifName[IF_NAMESIZE], *eptr;
  100 
  101     if (!AgentGetParameterArgA(param, 1, ifName, IF_NAMESIZE))
  102     {
  103         return SYSINFO_RC_ERROR;
  104     }
  105 
  106     // Check if we have interface name or index
  107     unsigned int ifIndex = (unsigned int)strtoul(ifName, &eptr, 10);
  108     if (*eptr == 0)
  109     {
  110         // Index passed as argument, convert to name
  111         if (if_indextoname(ifIndex, ifName) == NULL)
  112         {
  113             nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Unable to resolve interface index %u"), ifIndex);
  114             return SYSINFO_RC_ERROR;
  115         }
  116     }
  117 
  118     s_ifaceDataLock.lock();
  119 
  120     LONG nRet = SYSINFO_RC_SUCCESS;
  121     if (time(NULL) - s_ifaceDataTimestamp > 5)
  122     {
  123         if (!GetInterfaceData())
  124             nRet = SYSINFO_RC_ERROR;
  125     }
  126 
  127     if (nRet == SYSINFO_RC_SUCCESS)
  128     {
  129         int i;
  130         for(i = 0; i < s_ifaceDataSize; i++)
  131         {
  132             if (!strcmp(s_ifaceData[i].name, ifName))
  133                 break;
  134         }
  135         if (i < s_ifaceDataSize)
  136         {
  137             switch(CAST_FROM_POINTER(arg, int))
  138             {
  139                 case IF_INFO_DESCRIPTION:
  140                     ret_mbstring(value, s_ifaceData[i].description);
  141                     break;
  142                 case IF_INFO_MTU:
  143                     ret_int(value, s_ifaceData[i].mtu);
  144                     break;
  145                 case IF_INFO_SPEED:
  146                     ret_uint(value, s_ifaceData[i].bitrate);
  147                     break;
  148                 case IF_INFO_BYTES_IN:
  149                     ret_uint(value, s_ifaceData[i].ibytes);
  150                     break;
  151                 case IF_INFO_BYTES_OUT:
  152                     ret_uint(value, s_ifaceData[i].obytes);
  153                     break;
  154                 case IF_INFO_PACKETS_IN:
  155                     ret_uint(value, s_ifaceData[i].ipackets);
  156                     break;
  157                 case IF_INFO_PACKETS_OUT:
  158                     ret_uint(value, s_ifaceData[i].opackets);
  159                     break;
  160                 case IF_INFO_IN_ERRORS:
  161                     ret_uint(value, s_ifaceData[i].ierrors);
  162                     break;
  163                 case IF_INFO_OUT_ERRORS:
  164                     ret_uint(value, s_ifaceData[i].oerrors);
  165                     break;
  166                 default:
  167                     nRet = SYSINFO_RC_UNSUPPORTED;
  168                     break;
  169             }
  170         }
  171         else
  172         {
  173             nRet = SYSINFO_RC_UNSUPPORTED;
  174         }
  175     }
  176 
  177     s_ifaceDataLock.unlock();
  178     return nRet;
  179 }
  180 
  181 /**
  182  * Get MAC address and type for interface via getkerninfo()
  183  */
  184 static void GetNDDInfo(char *pszDevice, BYTE *pMacAddr, DWORD *pdwType)
  185 {
  186    int size = getkerninfo(KINFO_NDD, 0, 0, 0);
  187    if (size <= 0)
  188       return;  // getkerninfo() error
  189     
  190    struct kinfo_ndd *nddp = (struct kinfo_ndd *)MemAlloc(size);
  191    if (getkerninfo(KINFO_NDD, nddp, &size, 0) >= 0)
  192    {
  193       int nrec = size / sizeof(struct kinfo_ndd);
  194       for(int i = 0; i < nrec; i++)
  195       {
  196          if (!strcmp(pszDevice, nddp[i].ndd_name) ||
  197              !strcmp(pszDevice, nddp[i].ndd_alias))
  198          {
  199             memcpy(pMacAddr, nddp[i].ndd_addr, 6);
  200             *pdwType = nddp[i].ndd_type;
  201             break;
  202          }
  203       }
  204    }
  205    MemFree(nddp);
  206 }
  207 
  208 /**
  209  * Handler for Net.InterfaceNames enum
  210  */
  211 LONG H_NetInterfaceNames(const TCHAR *pszParam, const TCHAR *pArg, StringList *value, AbstractCommSession *session)
  212 {
  213    int sock = socket(AF_INET, SOCK_DGRAM, 0);
  214    if (sock <= 0)
  215       return SYSINFO_RC_ERROR;
  216 
  217    LONG nRet;
  218    int nrecs = 32;
  219    struct ifconf ifc;
  220 
  221 retry_ifconf:
  222    ifc.ifc_len = nrecs * sizeof(struct ifreq);
  223    ifc.ifc_buf = (caddr_t)MemAlloc(ifc.ifc_len);
  224 #ifdef OSIOCGIFCONF
  225    if (ioctl(sock, OSIOCGIFCONF, &ifc) == 0)
  226 #else
  227    if (ioctl(sock, SIOCGIFCONF, &ifc) == 0)
  228 #endif
  229    {
  230       if (ifc.ifc_len == nrecs * sizeof(struct ifconf))
  231       {
  232          // Assume overlolad, so increase buffer and retry
  233          MemFree(ifc.ifc_buf);
  234          nrecs += 32;
  235          goto retry_ifconf;
  236       }
  237 
  238       StringSet ifnames;
  239       nrecs = ifc.ifc_len / sizeof(struct ifreq);
  240       for(int i = 0; i < nrecs; i++)
  241       {
  242 #ifdef UNICODE
  243          ifnames.addPreallocated(WideStringFromMBString(ifc.ifc_req[i].ifr_name));
  244 #else
  245          ifnames.add(ifc.ifc_req[i].ifr_name);
  246 #endif
  247       }
  248 
  249       auto it = ifnames.iterator();
  250       while(it->hasNext())
  251       {
  252          value->add(it->next());
  253       }
  254       delete it;
  255 
  256       nRet = SYSINFO_RC_SUCCESS;
  257    }
  258    else
  259    {
  260       nRet = SYSINFO_RC_ERROR;
  261    }
  262 
  263    MemFree(ifc.ifc_buf);
  264    close(sock);
  265    return nRet;
  266 }
  267 
  268 /**
  269  * Handler for Net.InterfaceList enum
  270  */
  271 LONG H_NetInterfaceList(const TCHAR *pszParam, const TCHAR *pArg, StringList *value, AbstractCommSession *session)
  272 {
  273    int sock = socket(AF_INET, SOCK_DGRAM, 0);
  274    if (sock <= 0)
  275       return SYSINFO_RC_ERROR;
  276 
  277    LONG nRet;
  278    int nrecs = 32;
  279    struct ifconf ifc;
  280 
  281 retry_ifconf:
  282    ifc.ifc_len = nrecs * sizeof(struct ifreq);
  283    ifc.ifc_buf = (caddr_t)MemAlloc(ifc.ifc_len);
  284 #ifdef OSIOCGIFCONF
  285    if (ioctl(sock, OSIOCGIFCONF, &ifc) == 0)
  286 #else
  287    if (ioctl(sock, SIOCGIFCONF, &ifc) == 0)
  288 #endif
  289    {
  290       if (ifc.ifc_len == nrecs * sizeof(struct ifconf))
  291       {
  292          // Assume overlolad, so increase buffer and retry
  293          MemFree(ifc.ifc_buf);
  294          nrecs += 32;
  295          goto retry_ifconf;
  296       }
  297 
  298       nrecs = ifc.ifc_len / sizeof(struct ifreq);
  299       IF_INFO *ifl = MemAllocArray<IF_INFO>(nrecs);
  300       int nifs = 0;
  301       for(int i = 0; i < nrecs; i++)
  302       {
  303          // Check if interface already in internal table
  304          int j;
  305             for(j = 0; j < nifs; j++)
  306                 if (!strcmp(ifl[j].name, ifc.ifc_req[i].ifr_name) &&
  307                     (((ifc.ifc_req[i].ifr_addr.sa_family == AF_INET) && 
  308                       (((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr == ifl[j].ip)) ||
  309                      (ifc.ifc_req[i].ifr_addr.sa_family != AF_INET) ||
  310                      (ifl[j].ip == 0)))
  311                     break;
  312             if (j == nifs)
  313             {
  314                 strcpy(ifl[j].name, ifc.ifc_req[i].ifr_name);
  315                 GetNDDInfo(ifc.ifc_req[i].ifr_name, ifl[j].mac, &ifl[j].iftype);
  316                 nifs++;
  317             }
  318 
  319             // Copy IP address
  320             if (ifc.ifc_req[i].ifr_addr.sa_family == AF_INET)
  321             {
  322                 ifl[j].ip = ((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->sin_addr.s_addr;
  323              
  324             struct ifreq ifr;
  325                 strcpy(ifr.ifr_name, ifc.ifc_req[i].ifr_name);
  326                 ifr.ifr_addr.sa_family = AF_INET;
  327                 if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0)
  328                 {
  329                     ifl[j].netmask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  330                 }
  331             }
  332         }
  333 
  334         // Create result list
  335         for(int i = 0; i < nifs; i++)
  336         {
  337           char szBuffer[256], szIpAddr[16], szMacAddr[32];
  338             sprintf(szBuffer, "%d %s/%d %d %s %s",
  339                     if_nametoindex(ifl[i].name),
  340                     IpToStrA(ntohl(ifl[i].ip), szIpAddr),
  341                     BitsInMask(ifl[i].netmask), ifl[i].iftype,
  342                 BinToStrA(ifl[i].mac, 6, szMacAddr), ifl[i].name);
  343 #ifdef UNICODE
  344             value->addPreallocated(WideStringFromMBString(szBuffer));
  345 #else
  346             value->add(szBuffer);
  347 #endif
  348         }
  349         MemFree(ifl);
  350         nRet = SYSINFO_RC_SUCCESS;
  351     }
  352     else
  353     {
  354         nRet = SYSINFO_RC_ERROR;
  355     }
  356 
  357     MemFree(ifc.ifc_buf);
  358     close(sock);
  359     return nRet;
  360 }
  361 
  362 /**
  363  * Handler for Net.Interface.AdminStatus parameter
  364  */
  365 LONG H_NetInterfaceStatus(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
  366 {
  367     int nRet = SYSINFO_RC_ERROR;
  368     char ifName[IF_NAMESIZE], *eptr;
  369 
  370     AgentGetParameterArgA(param, 1, ifName, IF_NAMESIZE);
  371 
  372     // Check if we have interface name or index
  373     unsigned int ifIndex = (unsigned int)strtoul(ifName, &eptr, 10);
  374     if (*eptr == 0)
  375     {
  376         // Index passed as argument, convert to name
  377         if (if_indextoname(ifIndex, ifName) == NULL)
  378         {
  379             nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Unable to resolve interface index %u"), ifIndex);
  380             return SYSINFO_RC_ERROR;
  381         }
  382     }
  383 
  384     int requestedFlag = 0;
  385     switch(CAST_FROM_POINTER(arg, int))
  386     {
  387         case IF_INFO_ADMIN_STATUS:
  388             requestedFlag = IFF_UP;
  389             break;
  390         case IF_INFO_OPER_STATUS:
  391             requestedFlag = IFF_RUNNING;
  392             break;
  393         default:
  394             nxlog_debug_tag(AIX_DEBUG_TAG, 7, _T("Internal error in H_NetIfterfaceStatus (invalid flag requested)"));
  395             return SYSINFO_RC_ERROR;
  396     }
  397 
  398     int nSocket = socket(AF_INET, SOCK_DGRAM, 0);
  399     if (nSocket > 0)
  400     {
  401         struct ifreq ifr;
  402         int flags;
  403 
  404         memset(&ifr, 0, sizeof(ifr));
  405         strlcpy(ifr.ifr_name, ifName, sizeof(ifr.ifr_name));
  406         if (ioctl(nSocket, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
  407         {
  408             if ((ifr.ifr_flags & requestedFlag) == requestedFlag)
  409             {
  410                 // enabled
  411                 ret_int(value, 1);
  412                 nRet = SYSINFO_RC_SUCCESS;
  413             }
  414             else
  415             {
  416                 ret_int(value, 2);
  417                 nRet = SYSINFO_RC_SUCCESS;
  418             }
  419         }
  420         close(nSocket);
  421     }
  422 
  423     return nRet;
  424 }