"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/ifprop.c" (7 Jan 2023, 9907 Bytes) of package /linux/misc/atop-2.8.1.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 "ifprop.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.6.0_vs_2.7.0.

    1 /*
    2 ** ATOP - System & Process Monitor
    3 **
    4 ** The program 'atop' offers the possibility to view the activity of
    5 ** the system on system-level as well as process-level.
    6 **
    7 ** ==========================================================================
    8 ** Author:      Gerlof Langeveld
    9 ** E-mail:      gerlof.langeveld@atoptool.nl
   10 ** Date:        January 2007
   11 ** --------------------------------------------------------------------------
   12 ** Copyright (C) 2007-2010 Gerlof Langeveld
   13 **
   14 ** This program is free software; you can redistribute it and/or modify it
   15 ** under the terms of the GNU General Public License as published by the
   16 ** Free Software Foundation; either version 2, or (at your option) any
   17 ** later version.
   18 **
   19 ** This program is distributed in the hope that it will be useful, but
   20 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   22 ** See the GNU General Public License for more details.
   23 **
   24 ** You should have received a copy of the GNU General Public License
   25 ** along with this program; if not, write to the Free Software
   26 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   27 ** --------------------------------------------------------------------------
   28 */
   29 #include <sys/types.h>
   30 #include <stdio.h>
   31 #include <unistd.h>
   32 #include <stdlib.h>
   33 #include <string.h>
   34 #include <time.h>
   35 #include <sys/socket.h>
   36 #include <sys/ioctl.h>
   37 #include <linux/sockios.h>
   38 #include <linux/if.h>
   39 #include <linux/in.h>
   40 #include <dirent.h>
   41 
   42 typedef __u64   u64;
   43 typedef __u32   u32;
   44 typedef __u16   u16;
   45 typedef __u8    u8;
   46 #include <linux/ethtool.h>
   47 #include <linux/wireless.h>
   48 
   49 #ifndef SPEED_UNKNOWN
   50 #define SPEED_UNKNOWN   -1
   51 #endif
   52 
   53 #include "atop.h"
   54 #include "ifprop.h"
   55 #include "photosyst.h"
   56 
   57 static int      calcbucket(char *);
   58 static int      getphysprop(struct ifprop *);
   59 
   60 /*
   61 ** hash table for linked lists with *all* interfaces
   62 ** of this system (including virtual interfaces), even
   63 ** if the number of interfaces exceeds the maximum that
   64 ** is supported by atop (MAXINTF)
   65 ** when the number of interfaces in the system exceeds MAXINTF,
   66 ** preferably virtual interfaces are marked 'invalid' to ensure
   67 ** that all physical interfaces are reported
   68 **
   69 ** the hash table is meant to be searched on interface name
   70 */
   71 #define NUMIFHASH   256 // must be power of 2!!
   72 static struct ifprop    *ifhash[NUMIFHASH];
   73 
   74 /*
   75 ** refresh interval of ifhash table
   76 **
   77 ** periodic refreshing is needed because interfaces might have been
   78 ** created or removed, or the speed might have changed (e.g. with wireless)
   79 */
   80 #define REFRESHTIME 60      // seconds
   81 static time_t       lastrefreshed;  // epoch
   82 
   83 /*
   84 ** function that searches for the properties of a particular interface;
   85 ** the interface name should be filled in the struct ifprop before
   86 ** calling this function
   87 **
   88 ** return value reflects true (valid interface) or false (invalid interface)
   89 */
   90 int
   91 getifprop(struct ifprop *p)
   92 {
   93     register int    bucket;
   94     struct ifprop   *ifp;
   95 
   96     /*
   97     ** search properties related to given interface name
   98     */
   99     bucket = calcbucket(p->name);
  100 
  101     for (ifp=ifhash[bucket]; ifp; ifp=ifp->next)
  102     {
  103         if ( strcmp(ifp->name, p->name) == EQ )
  104         {
  105             if (ifp->type == 'i')   // invalidated interface?
  106                 break;
  107 
  108             // valid interface; copy properties
  109             *p = *ifp;
  110             return 1;
  111         }
  112     }
  113 
  114     p->type     = '?';
  115     p->speed    = 0;
  116     p->fullduplex   = 0;
  117 
  118     return 0;
  119 }
  120 
  121 /*
  122 ** function (re)stores properties of all interfaces in a hash table
  123 */
  124 void
  125 initifprop(void)
  126 {
  127     FILE        *fp;
  128     char        *cp, linebuf[2048];
  129     struct ifprop   *ifp, *ifpsave = NULL;
  130     int     bucket, nrinterfaces=0, nrphysical=0;
  131 
  132     DIR     *dirp;
  133     struct dirent   *dentry;
  134 
  135     /*
  136     ** verify if the interface properties have to be refreshed
  137     ** at this moment already
  138     */
  139     if (time(0) < lastrefreshed + REFRESHTIME)
  140         return;
  141 
  142     /*
  143     ** when this function has been called before, first remove
  144     ** old entries
  145     */
  146     if (lastrefreshed)
  147     {
  148         for (bucket=0; bucket < NUMIFHASH; bucket++)
  149         {
  150             for (ifp = ifhash[bucket]; ifp; ifp = ifpsave)
  151             {
  152                 ifpsave = ifp->next;
  153                 free(ifp);
  154             }
  155     
  156             ifhash[bucket] = NULL;
  157         }
  158     }
  159 
  160     /*
  161     ** open /proc/net/dev and read all interface names to be able to
  162     ** setup new entries in the hash table
  163     */
  164     if ( (fp = fopen("/proc/net/dev", "r")) == NULL)
  165         return;
  166 
  167     while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  168     {
  169         /*
  170         ** skip lines containing a '|' symbol (headers)
  171         */
  172         if ( strchr(linebuf, '|') != NULL)
  173             continue;
  174 
  175         if ( (cp = strchr(linebuf, ':')) != NULL)
  176             *cp = ' ';    /* subst ':' by space */
  177 
  178         /*
  179         ** allocate new ifprop struct for this interface
  180         */
  181         ifp = malloc(sizeof *ifp);
  182 
  183         ptrverify(ifp, "Malloc failed for ifprop struct\n");
  184 
  185         memset(ifp, 0, sizeof *ifp);
  186         sscanf(linebuf, "%30s", ifp->name); // fill name
  187         ifp->type = 'i';            // initially 'invalid'
  188 
  189         /*
  190         ** add ifprop struct to proper hash bucket
  191         */
  192         bucket = calcbucket(ifp->name);
  193 
  194         ifp->next = ifhash[bucket];
  195         ifhash[bucket] = ifp;
  196 
  197         nrinterfaces++;
  198     }
  199 
  200     fclose(fp);
  201 
  202     /*
  203     ** read /sys/devices/virtual/net/xxx to determine which
  204     ** interfaces are virtual (xxx is subdirectory name)
  205     */
  206     if ( (dirp = opendir("/sys/devices/virtual/net")) )
  207     {
  208         while ( (dentry = readdir(dirp)) )
  209         {
  210             if (dentry->d_name[0] == '.')
  211                 continue;
  212     
  213             // valid name
  214             // search ifprop and mark it as 'virtual'
  215             bucket = calcbucket(dentry->d_name);
  216 
  217             for (ifp = ifhash[bucket]; ifp; ifp = ifp->next)
  218             {
  219                 if ( strcmp(ifp->name, dentry->d_name) == EQ )
  220                 {
  221                     ifp->type = 'v'; // virtual interface
  222                     break;
  223                 }
  224             }
  225         }
  226 
  227         closedir(dirp);
  228     }
  229 
  230 
  231     /*
  232     ** for physical interfaces, determine the speed and duplex mode
  233     */
  234     for (bucket=0; bucket < NUMIFHASH; bucket++)
  235     {
  236         for (ifp=ifhash[bucket]; ifp; ifp=ifp->next)
  237         {
  238             // possible physical interface?
  239             if (ifp->type == 'i')
  240             {
  241                 if (getphysprop(ifp))
  242                     nrphysical++;
  243             }
  244         }
  245     }
  246 
  247     lastrefreshed = time(0);
  248 
  249     if (nrinterfaces < MAXINTF)
  250         return;
  251 
  252     /*
  253     ** when the number of interfaces exceeds the maximum,
  254     ** invalidate the appropriate number of interfaces (preferably
  255     ** virtual interfaces)
  256     */
  257     for (bucket=0; bucket < NUMIFHASH && nrinterfaces >= MAXINTF; bucket++)
  258     {
  259         for (ifp=ifhash[bucket]; ifp && nrinterfaces >= MAXINTF; ifp=ifp->next)
  260         {
  261             // interface invalid already?
  262             if (ifp->type == 'i')
  263             {
  264                 nrinterfaces--;
  265                 continue;
  266             }
  267 
  268             // physical interface (ethernet or wireless)?
  269             if (ifp->type == 'e' || ifp->type == 'w')
  270             {
  271                 // only invalidate when the number of physical
  272                 // interfaces exceeds MAXINTF
  273                 if (nrphysical >= MAXINTF)
  274                 {
  275                     ifp->type = 'i';
  276 
  277                     nrphysical--;
  278                     nrinterfaces--;
  279                 }
  280                 continue;
  281             }
  282 
  283             // virtual or unknown interface, invalidate anyhow
  284             ifp->type = 'i';
  285             nrinterfaces--;
  286         }
  287     }
  288 }
  289 
  290 static int
  291 calcbucket(char *p)
  292 {
  293     int bucket = 0;
  294 
  295     while (*p)
  296         bucket += *p++;
  297 
  298     return bucket & (NUMIFHASH-1);
  299 }
  300 
  301 /*
  302 ** function gathers the properties of a particular physical interface;
  303 ** the name of the interface should have been filled before calling
  304 **
  305 ** return value reflects true (success) or false (unknown interface type)
  306 */
  307 static int
  308 getphysprop(struct ifprop *p)
  309 {
  310     int sockfd;
  311 
  312 #ifdef ETHTOOL_GLINKSETTINGS
  313     struct ethtool_link_settings    *ethlink;   // preferred!
  314 #endif
  315     struct ethtool_cmd      ethcmd;     // deprecated   
  316 
  317     struct ifreq            ifreq;
  318     struct iwreq            iwreq;
  319 
  320     unsigned long           speed = 0;
  321     unsigned char           duplex = 0, ethernet = 0;
  322 
  323 
  324     if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  325         return 0;
  326 
  327     /*
  328     ** determine properties of ethernet interface
  329     ** preferably with actual struct ethtool_link_settings,
  330     ** otherwise with deprecated struct ethtool_cmd
  331     */
  332     memset(&ifreq,  0, sizeof ifreq);
  333 
  334     strncpy((void *)&ifreq.ifr_ifrn.ifrn_name, p->name,
  335             sizeof ifreq.ifr_ifrn.ifrn_name-1);
  336 
  337 #ifdef ETHTOOL_GLINKSETTINGS
  338     ethlink = calloc(1, sizeof *ethlink);
  339 
  340     ptrverify(ethlink, "Calloc failed for ethtool_link_settings\n");
  341 
  342     ethlink->cmd = ETHTOOL_GLINKSETTINGS;
  343 
  344     ifreq.ifr_ifru.ifru_data = (void *)ethlink;
  345 
  346     if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) == 0)
  347     {
  348         if (ethlink->link_mode_masks_nwords <= 0)
  349         {
  350             /*
  351             ** hand shaked ethlink required with added maps
  352             **
  353             ** layout of link_mode_masks fields:
  354             ** __u32 map_supported[link_mode_masks_nwords];
  355             ** __u32 map_advertising[link_mode_masks_nwords];
  356             ** __u32 map_lp_advertising[link_mode_masks_nwords];
  357             */
  358             ethlink->link_mode_masks_nwords = -ethlink->link_mode_masks_nwords;
  359 
  360             ethlink = realloc(ethlink, sizeof *ethlink +
  361                           3 * sizeof(__u32) * ethlink->link_mode_masks_nwords);
  362 
  363             ptrverify(ethlink, "Realloc failed for ethtool_link_settings\n");
  364 
  365             ifreq.ifr_ifru.ifru_data = (void *)ethlink; // might have changed
  366 
  367             if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) != 0 )
  368             {
  369                 close(sockfd);
  370                 free(ethlink);
  371                 return 0;
  372             }
  373         }
  374 
  375         ethernet = 1;
  376         speed    = ethlink->speed;
  377         duplex   = ethlink->duplex;
  378 
  379         free(ethlink);
  380     }
  381     else
  382 #endif
  383     {
  384         memset(&ethcmd, 0, sizeof ethcmd);
  385 
  386         ethcmd.cmd               = ETHTOOL_GSET;
  387         ifreq.ifr_ifru.ifru_data = (void *)&ethcmd;
  388 
  389         if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) == 0) 
  390         {
  391             ethernet = 1;
  392             speed    = ethcmd.speed;
  393             duplex   = ethcmd.duplex;
  394         }
  395     }
  396 
  397     if (ethernet)
  398     {
  399         p->type  = 'e'; // type ethernet
  400 
  401         if (speed == (u32)SPEED_UNKNOWN || speed == 65535)
  402             p->speed = 0;
  403         else
  404             p->speed = speed;
  405 
  406         switch (duplex)
  407         {
  408            case DUPLEX_FULL:
  409             p->fullduplex   = 1;
  410             break;
  411            default:
  412             p->fullduplex   = 0;
  413         }
  414     }
  415     else
  416     {
  417         /*
  418         ** determine properties of wireless interface
  419         */
  420         memset(&iwreq,  0, sizeof iwreq);
  421 
  422         strncpy(iwreq.ifr_ifrn.ifrn_name, p->name,
  423                 sizeof iwreq.ifr_ifrn.ifrn_name-1);
  424 
  425         if ( ioctl(sockfd, SIOCGIWRATE, &iwreq) == 0) 
  426         {
  427             p->type         = 'w';  // type wireless
  428             p->fullduplex   = 0;
  429             p->speed    = (iwreq.u.bitrate.value + 500000) / 1000000;
  430         }
  431         else
  432         {
  433             p->type         = '?';  // type unknown
  434             p->fullduplex   = 0;
  435             p->speed    = 0;
  436         }
  437     }
  438 
  439     close(sockfd);
  440 
  441     return 1;
  442 }