From 028754e08bbbc6c906ce702fdebdc75f785d3037 Mon Sep 17 00:00:00 2001 From: Aaron LI Date: Fri, 26 Jun 2020 21:38:11 +0800 Subject: [PATCH] ifconfig(8): Speed up non-status operations to a single interface When performing a non-status operation on a single interface (e.g., set address or flags), it is not necessary for ifconfig(8) to build a list of all addresses in the system, sort them, and then iterate through them to look for the single interface of interest. Obtained from FreeBSD (revision 343535; review D18919) --- sbin/ifconfig/ifconfig.c | 53 +++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 9ae9243172..b0a111173f 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -95,6 +95,7 @@ static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, static void tunnel_status(int s); static void usage(void) __dead2; +static int getifflags(const char *ifname, int us); static struct afswtch *af_getbyname(const char *name); static struct afswtch *af_getbyfamily(int af); static void af_other_status(int); @@ -351,7 +352,7 @@ int main(int argc, char *argv[]) { int c, all, namesonly, downonly, uponly; - int ifindex; + int ifindex, flags; const struct afswtch *afp = NULL; const struct sockaddr_dl *sdl; const char *ifname; @@ -501,6 +502,25 @@ main(int argc, char *argv[]) argc--, argv++; } + /* + * Check for a requested configuration action on a single interface, + * which doesn't require building, sorting, and searching the entire + * system address list. + */ + if (argc > 0 && ifname != NULL) { + iflen = strlcpy(name, ifname, sizeof(name)); + if (iflen >= sizeof(name)) + errx(1, "%s: cloning name too long", ifname); + + flags = getifflags(name, -1); + if (!((downonly && (flags & IFF_UP) != 0) || + (uponly && (flags & IFF_UP) == 0))) { + ifconfig(argc, argv, 0, afp); + } + + exit(exit_code); + } + if (getifaddrs(&ifap) != 0) err(1, "getifaddrs"); if (calcorders(ifap, &q) != 0) @@ -936,25 +956,46 @@ setifdstaddr(const char *addr, int param __unused, int s, afp->af_getaddr(addr, DSTADDR); } -static void -setifflags(const char *vname, int value, int s, const struct afswtch *afp) +static int +getifflags(const char *ifname, int us) { struct ifreq my_ifr; - int flags; + int s; memset(&my_ifr, 0, sizeof(struct ifreq)); - strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); + strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name)); + + s = us; + if (us < 0) { + if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) + err(1, "socket(family AF_LOCAL,SOCK_DGRAM)"); + } if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) Perror("ioctl (SIOCGIFFLAGS)"); - flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); + if (us < 0) + close(s); + + return ((my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16)); +} + +static void +setifflags(const char *vname, int value, int s, const struct afswtch *afp) +{ + struct ifreq my_ifr; + int flags; + + flags = getifflags(name, s); if (value < 0) { value = -value; flags &= ~value; } else { flags |= value; } + + memset(&my_ifr, 0, sizeof(struct ifreq)); + strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); my_ifr.ifr_flags = flags & 0xffff; my_ifr.ifr_flagshigh = flags >> 16; if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) -- 2.41.0