Speed up list operations by exploiting that the interface list is ordered,
authorAndi Kleen <andi@firstfloor.org>
Mon, 14 Aug 2000 07:57:19 +0000 (07:57 +0000)
committerAndi Kleen <andi@firstfloor.org>
Mon, 14 Aug 2000 07:57:19 +0000 (07:57 +0000)
and the kernel list is normally ordered to.

This allows to list 7000 aliases in a reasonable time.
Also be a bit smarter on when to read SIOCGIFCONF.

The stupid IPv6 /proc parsing on every address still burns a lot of CPU
time.

ifconfig.c
include/interface.h
lib/interface.c

index fb83a26..d23982b 100644 (file)
@@ -3,7 +3,7 @@
  *              that either displays or sets the characteristics of
  *              one or more of the system's networking interfaces.
  *
- * Version:     $Id: ifconfig.c,v 1.40 2000/07/31 01:13:33 ecki Exp $
+ * Version:     $Id: ifconfig.c,v 1.41 2000/08/14 07:57:19 ak Exp $
  *
  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  *              and others.  Copyright 1993 MicroWalt Corporation
@@ -112,7 +112,7 @@ static int if_print(char *ifname)
     } else {
        struct interface *ife;
 
-       ife = lookup_interface(ifname,1);
+       ife = lookup_interface(ifname);
        res = do_if_fetch(ife); 
        if (res >= 0) 
            ife_print(ife);
@@ -1037,7 +1037,7 @@ static int get_nmbc_parent(char *parent,
        struct interface *i;
        struct sockaddr_in *sin;
 
-       i = lookup_interface(parent, 1);
+       i = lookup_interface(parent);
        if (!i)
                return -1;
        if (do_if_fetch(i) < 0)
index bd1b948..45d4ac2 100644 (file)
@@ -28,8 +28,7 @@ struct user_net_device_stats {
 };
 
 struct interface {
-    struct interface *next;
-
+    struct interface *next, *prev; 
     char name[IFNAMSIZ];       /* interface name        */
     short type;                        /* if type               */
     short flags;               /* various flags         */
@@ -66,7 +65,7 @@ extern int if_fetch(struct interface *ife);
 
 extern int for_all_interfaces(int (*)(struct interface *, void *), void *);
 extern int free_interface_list(void);
-extern struct interface *lookup_interface(char *name, int readlist);
+extern struct interface *lookup_interface(char *name);
 extern int if_readlist(void);
 
 extern int do_if_fetch(struct interface *ife);
index f800dbd..ac74eb3 100644 (file)
@@ -4,7 +4,10 @@
    10/1998 partly rewriten by Andi Kleen to support an interface list.   
    I don't claim that the list operations are efficient @).  
 
-   $Id: interface.c,v 1.9 2000/05/21 19:35:34 pb Exp $
+   8/2000  Andi Kleen make the list operations a bit more efficient.
+   People are crazy enough to use thousands of aliases now.
+
+   $Id: interface.c,v 1.10 2000/08/14 07:57:19 ak Exp $
  */
 
 #include "config.h"
@@ -84,38 +87,41 @@ int procnetdev_vsn = 1;
 
 int ife_short;
 
-static struct interface *int_list;
+static struct interface *int_list, *int_last;
 
-void add_interface(struct interface *n)
-{
-    struct interface *ife, **pp;
+static int if_readlist_proc(char *);
 
-    pp = &int_list;
-    for (ife = int_list; ife; pp = &ife->next, ife = ife->next) {
-       if (nstrcmp(ife->name, n->name) > 0)
-           break;
+static struct interface *add_interface(char *name)
+{
+    struct interface *ife, **nextp, *new;
+
+    for (ife = int_last; ife; ife = ife->prev) {
+           int n = nstrcmp(ife->name, name); 
+           if (n == 0) 
+                   return ife; 
+           if (n < 0) 
+                   break; 
     }
-    n->next = (*pp);
-    (*pp) = n;
+    new(new); 
+    safe_strncpy(new->name, name, IFNAMSIZ); 
+    nextp = ife ? &ife->next : &int_list;
+    new->prev = ife;
+    new->next = *nextp; 
+    if (new->next) 
+           new->next->prev = new; 
+    else
+           int_last = new; 
+    *nextp = new; 
+    return new; 
 }
 
-struct interface *lookup_interface(char *name, int readlist)
+struct interface *lookup_interface(char *name)
 {
     struct interface *ife = NULL;
 
-    if (int_list || (readlist && if_readlist() >= 0)) {
-               for (ife = int_list; ife; ife = ife->next) {
-               if (!strcmp(ife->name, name))
-                       break;
-               }
-    }
-
-    if (!ife) { 
-       new(ife);
-       safe_strncpy(ife->name, name, IFNAMSIZ);  
-       add_interface(ife);
-    }
-
+    if (if_readlist_proc(name) < 0) 
+           return NULL; 
+    ife = add_interface(name); 
     return ife;
 }
 
@@ -182,7 +188,7 @@ static int if_readconf(void)
 
     ifr = ifc.ifc_req;
     for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
-       lookup_interface(ifr->ifr_name,0);
+       add_interface(ifr->ifr_name);
        ifr++;
     }
     err = 0;
@@ -292,13 +298,19 @@ static int get_dev_fields(char *bp, struct interface *ife)
     return 0;
 }
 
-int if_readlist(void)
+static int if_readlist_proc(char *target)
 {
+    static int proc_read; 
     FILE *fh;
     char buf[512];
     struct interface *ife;
     int err;
 
+    if (proc_read) 
+           return 0; 
+    if (!target) 
+           proc_read = 1;
+
     fh = fopen(_PATH_PROCNET_DEV, "r");
     if (!fh) {
                fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
@@ -336,22 +348,19 @@ int if_readlist(void)
 
     err = 0;
     while (fgets(buf, sizeof buf, fh)) {
-       char *s;
-
-       new(ife);
-
-       s = get_name(ife->name, buf);
+       char *s, name[IFNAMSIZ];
+       s = get_name(name, buf);    
+       ife = add_interface(name);
        get_dev_fields(s, ife);
        ife->statistics_valid = 1;
-
-       add_interface(ife);
+       if (target && !strcmp(target,name))
+               break;
     }
     if (ferror(fh)) {
        perror(_PATH_PROCNET_DEV);
        err = -1;
+       proc_read = 0; 
     }
-    if (!err)
-       err = if_readconf();
 
 #if 0
     free(fmt);
@@ -360,6 +369,14 @@ int if_readlist(void)
     return err;
 }
 
+int if_readlist(void) 
+{ 
+    int err = if_readlist_proc(NULL); 
+    if (!err)
+           err = if_readconf();
+    return err;
+} 
+
 /* Support for fetching an IPX address */
 
 #if HAVE_AFIPX