From owner-freebsd-hackers@FreeBSD.ORG Wed Mar 26 21:24:32 2014 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 521CF518 for ; Wed, 26 Mar 2014 21:24:32 +0000 (UTC) Received: from mail-vc0-x232.google.com (mail-vc0-x232.google.com [IPv6:2607:f8b0:400c:c03::232]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 1448BE3F for ; Wed, 26 Mar 2014 21:24:32 +0000 (UTC) Received: by mail-vc0-f178.google.com with SMTP id im17so3171225vcb.37 for ; Wed, 26 Mar 2014 14:24:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=8agcRqkj4cPc36fmed5DEGjObKlj0kk2wtUG3w6xACQ=; b=jOiaxqgUlh7ZVzNhtuZek1ax5T0sXUviEe2sErDP2NFO15m1gcQCSVe5K5vw01jr8j XOO4Y1l5wYTkt7rEoyOQOPm0dQ+OvWw/nrDcPtb+dbHAs75oseIYBpNiffH8CkcTGdRA 0PWtLfsdayCnO182IhaqEPdNp9pEw8Dm02sxwf7A1PThfDwPwi+jssF4tnYjr6F31gyV KYvrrsRgiT5iPRQARH+EUmTE1DnllhErdaWU9fbfw9poKz8x5claIjZUPquEdVWKtz1w pDok7llQsngBgKANsmKqdfsSL1wL4WmuVi7J1fC80M9oUxUjhR0dajjtJ4V46gGMoALV Qgeg== MIME-Version: 1.0 X-Received: by 10.58.181.170 with SMTP id dx10mr2064047vec.25.1395869071073; Wed, 26 Mar 2014 14:24:31 -0700 (PDT) Received: by 10.52.106.170 with HTTP; Wed, 26 Mar 2014 14:24:31 -0700 (PDT) Date: Wed, 26 Mar 2014 14:24:31 -0700 Message-ID: Subject: arp(8) performance - use if_nameindex() instead of if_indextoname() From: Nick Rogers To: freebsd-hackers@freebsd.org Content-Type: text/plain; charset=ISO-8859-1 X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Mar 2014 21:24:32 -0000 This is in reference to an old thread in this list referenced here: http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg157105.html Running arp -na from a shell can still take a very long time to complete on systems with thousands of VLAN interfaces and ARP entries. This is because if_indextoname() is an extremely heavy (slow) operation, and it is called for every ARP entry in src/usr.sbin/arp/arp.c. The following commit addressed a similar issue when many aliases were configured on a given interface, however as Adrian Chadd pointed out, does not help for cases where the interface name alternates between entries. This is exactly what happens when many VLANs interfaces exist, and each has only one IP alias. http://svnweb.freebsd.org/base?view=revision&revision=209063 I propose that instead of calling if_indextoname() for every entry, we leverage if_nameindex() to obtain a cache of if_index to if_name mappings, before printing all the entries. This results in a considerable performance improvement for my situation, and also handles the case that was "fixed" in the commit I just mentioned. I took a shot at this and came up with the following diff against HEAD. I used routed's route6d.c as a reference, which is the only thing I could find utilizing if_nameindex(). I am currently using this in production environments with great success. Index: usr.sbin/arp/arp.c =================================================================== --- arp.c (revision 263777) +++ arp.c (working copy) @@ -104,6 +104,8 @@ static time_t expire_time; static int flags, doing_proxy, proxy_only; +struct if_nameindex *ifnameindex; + /* which function we're supposed to do */ #define F_GET 1 #define F_SET 2 @@ -204,6 +206,9 @@ break; } +if (ifnameindex != NULL) + if_freenameindex(ifnameindex); + return (rtn); } @@ -557,13 +562,15 @@ /* * Display an arp entry */ -static char lifname[IF_NAMESIZE]; -static int64_t lifindex = -1; static void print_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr, struct rt_msghdr *rtm) { + + if (ifnameindex == NULL) + ifnameindex = if_nameindex(); + const char *host; struct hostent *hp; struct iso88025_sockaddr_dl_data *trld; @@ -595,12 +602,15 @@ } } else printf("(incomplete)"); - if (sdl->sdl_index != lifindex && - if_indextoname(sdl->sdl_index, lifname) != NULL) { - lifindex = sdl->sdl_index; - printf(" on %s", lifname); - } else if (sdl->sdl_index == lifindex) - printf(" on %s", lifname); + + struct if_nameindex *p; + for (p = ifnameindex; p && ifnameindex->if_index && ifnameindex->if_name; p++) { + if (p->if_index == sdl->sdl_index) { + printf(" on %s", p->if_name); + break; + } + } + if (rtm->rtm_rmx.rmx_expire == 0) printf(" permanent"); else { The following illustrates the performance improvement: [root@vm ~/arp]# ifconfig -a | grep vlan | grep interface | wc -l 1500 [root@vm ~/arp]# arp -na | wc -l 1503 [root@vm ~/arp]# time /usr/sbin/arp.old -na > /dev/null real 0m5.529s user 0m0.813s sys 0m4.231s [root@vm ~/arp]# time /usr/sbin/arp -na > /dev/null real 0m0.011s user 0m0.008s sys 0m0.002s [root@vm ~/arp]# I realize this may not be the cleanest way of implementing if_nameindex within arp.c. I'm hoping Max Laier or someone else can help me out (again) and get an adequate fix committed. Thanks! -Nick Rogers