On Sun, Aug 13, 2000 at 12:40:53PM -0400, Dennis wrote: > At 04:49 AM 8/13/00 +0200, Sven Koch wrote: > >On Sun, 13 Aug 2000, Andi Kleen wrote: > > > >> > The number of IP addresses on one interface in kernel 2.2.x is only > >> > limited by physical memory as far as I can tell. In a test I was able to > >> > assign over 7000 numbers to one eth - worked without problems, only > >> > ifconfig took nearly 10 minutes to get me a list (old 233mhz machine > >> > with suse 6.4 and suse kernel 2.2.14) > >> > >> The 10 minutes were probably caused by the name resolver in ifconfig. > >> Try ifconfig -n > > I dont believe there is a name lookup with ifconfig. We see the same issue > with ifconfig with 1000 DLCIs with no IP addresses assigned at all. Its > something in the way that ifconfig gets the info...ifconfig on other OSs > with similar setups return with no additional delay. > > I could understand if you did a -a, but there is really no good > explanation of why an ifconfig on a specific interface would take so long > to get the info. I reported it a while back without much interest. You apparently did not report it to the maintainers (just sending it to lists may cause it being lost) ifconfig has to read full /proc/net/dev to find out if the device has statistics or not. It also did read the whole address list in the same go, making ifconfig name equivalent to ifconfig -a. It also did some inefficient list operations, because it was never designed for thousands of interfaces. The following patch should fix it. It makes the list operations a lot more efficient by exploiting the sorting order (as long as your aliases are numerically sorted in the system insert is O(1)), and does less work when you specified a device name. Listing 7000 ordered aliases takes about 90s on a K6-4000 now. -Andi Index: ifconfig.c =================================================================== RCS file: /cvs/net-tools/ifconfig.c,v retrieving revision 1.40 diff -u -u -r1.40 ifconfig.c --- ifconfig.c 2000/07/31 01:13:33 1.40 +++ ifconfig.c 2000/08/13 23:16:43 @@ -112,7 +112,7 @@ } 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 @@ 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: include/interface.h =================================================================== RCS file: /cvs/net-tools/include/interface.h,v retrieving revision 1.4 diff -u -u -r1.4 interface.h --- include/interface.h 2000/05/21 19:35:34 1.4 +++ include/interface.h 2000/08/13 23:16:43 @@ -28,8 +28,7 @@ }; 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 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: lib/interface.c =================================================================== RCS file: /cvs/net-tools/lib/interface.c,v retrieving revision 1.9 diff -u -u -r1.9 interface.c --- lib/interface.c 2000/05/21 19:35:34 1.9 +++ lib/interface.c 2000/08/13 23:16:44 @@ -4,6 +4,9 @@ 10/1998 partly rewriten by Andi Kleen to support an interface list. I don't claim that the list operations are efficient @). + 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.9 2000/05/21 19:35:34 pb Exp $ */ @@ -83,39 +86,42 @@ int procnetdev_vsn = 1; int ife_short; + +static struct interface *int_list, *int_last; -static struct interface *int_list; +static int if_readlist_proc(char *); -void add_interface(struct interface *n) +static struct interface *add_interface(char *name) { - struct interface *ife, **pp; + struct interface *ife, **nextp, *new; - pp = &int_list; - for (ife = int_list; ife; pp = &ife->next, ife = ife->next) { - if (nstrcmp(ife->name, n->name) > 0) - break; - } - n->next = (*pp); - (*pp) = n; + for (ife = int_last; ife; ife = ife->prev) { + int n = nstrcmp(ife->name, name); + if (n == 0) + return ife; + if (n < 0) + break; + } + 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 @@ 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 @@ 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 @@ 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); @@ -359,6 +368,14 @@ fclose(fh); 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 */ - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.rutgers.edu