Implementing SIOCGIFNAME for Linuxulator. Design notes: - use a separated counter 'ethno' to keep the number of ether devices rather than mixing it up with 'index' or the result will be inconsistent with linprocfs/net/dev. Consider the following example: $ ifconfig | grep '^[a-z]' em0: flags=8843 metric 0 mtu 1500 ath0: flags=8802 metric 0 mtu 2290 lo0: flags=8049 metric 0 mtu 16384 wlan0: flags=8802 metric 0 mtu 1500 Doing a Linux ioctl(SIOCGIFNAME) with ifr.ifr_ifindex from 1 ~ 4 on the above system will yield: eth0, ath0, lo0 and eth1(the correct behaviour). On the other hand, if one removes ethno and uses index instead, the result will be: eth0, ath0, lo0 and eth3. - According to Linux's if.h, ifr_ifru.ifru_metric should be renamed to ifr_ifru.ifru_ivalue. Given that there is no in-kernel consumer of l_ifreq::ifr_ifru.ifru_metric, it may be safe for us to introduce ifr_ifru.ifru_ivalue and turn ifr_ifru.ifru_metric into an alias of ifru_ivalue in a separated commit. Reviewed by: kib, marcel Index: amd64/linux32/linux.h =================================================================== --- amd64/linux32/linux.h (revision 254893) +++ amd64/linux32/linux.h (working copy) @@ -654,6 +654,11 @@ #define ifr_name ifr_ifrn.ifrn_name /* Interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +/* + * XXX: In Linux, there is no ifr_ifru.ifru_metric but a ifr_ifru.ifru_ivalue + * instead. For now we just keep our own naming to avoid API breakage. + */ +#define ifr_ifindex ifr_ifru.ifru_metric /* Interface index */ struct l_ifconf { int ifc_len; Index: compat/linux/linux_ioctl.c =================================================================== --- compat/linux/linux_ioctl.c (revision 254893) +++ compat/linux/linux_ioctl.c (working copy) @@ -2157,6 +2157,49 @@ } /* + * Implement the SIOCGIFNAME ioctl + */ + +static int +linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr) +{ + struct l_ifreq ifr; + struct ifnet *ifp; + int error, ethno, index; + + error = copyin(uifr, &ifr, sizeof(ifr)); + if (error != 0) + return (error); + + CURVNET_SET(TD_TO_VNET(curthread)); + IFNET_RLOCK(); + index = 1; /* ifr.ifr_ifindex starts from 1 */ + ethno = 0; + error = ENODEV; + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + if (ifr.ifr_ifindex == index) { + if (IFP_IS_ETH(ifp)) + snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, + "eth%d", ethno); + else + strlcpy(ifr.ifr_name, ifp->if_xname, + LINUX_IFNAMSIZ); + error = 0; + break; + } + if (IFP_IS_ETH(ifp)) + ethno++; + index++; + } + IFNET_RUNLOCK(); + if (error == 0) + error = copyout(&ifr, uifr, sizeof(ifr)); + CURVNET_RESTORE(); + + return (error); +} + +/* * Implement the SIOCGIFCONF ioctl */ @@ -2381,6 +2424,7 @@ case LINUX_SIOCADDMULTI: case LINUX_SIOCATMARK: case LINUX_SIOCDELMULTI: + case LINUX_SIOCGIFNAME: case LINUX_SIOCGIFCONF: case LINUX_SIOCGPGRP: case LINUX_SIOCSPGRP: @@ -2466,6 +2510,10 @@ /* LINUX_SIOCGSTAMP */ + case LINUX_SIOCGIFNAME: + error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg); + break; + case LINUX_SIOCGIFCONF: error = linux_ifconf(td, (struct ifconf *)args->arg); break; Index: compat/linux/linux_ioctl.h =================================================================== --- compat/linux/linux_ioctl.h (revision 254893) +++ compat/linux/linux_ioctl.h (working copy) @@ -226,6 +226,7 @@ #define LINUX_SIOCGPGRP 0x8904 #define LINUX_SIOCATMARK 0x8905 #define LINUX_SIOCGSTAMP 0x8906 +#define LINUX_SIOCGIFNAME 0x8910 #define LINUX_SIOCGIFCONF 0x8912 #define LINUX_SIOCGIFFLAGS 0x8913 #define LINUX_SIOCGIFADDR 0x8915 Index: i386/linux/linux.h =================================================================== --- i386/linux/linux.h (revision 254893) +++ i386/linux/linux.h (working copy) @@ -630,6 +630,11 @@ #define ifr_name ifr_ifrn.ifrn_name /* Interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +/* + * XXX: In Linux, there is no ifr_ifru.ifru_metric but a ifr_ifru.ifru_ivalue + * instead. For now we just keep our own naming to avoid API breakage. + */ +#define ifr_ifindex ifr_ifru.ifru_metric /* Interface index */ /* * poll()