The branch main has been updated by jhibbits:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=52d984831d82d97dc132d0d57fca6ee89572799b

commit 52d984831d82d97dc132d0d57fca6ee89572799b
Author:     Justin Hibbits <jhibb...@freebsd.org>
AuthorDate: 2023-02-01 21:30:22 +0000
Commit:     Justin Hibbits <jhibb...@freebsd.org>
CommitDate: 2023-02-14 15:28:44 +0000

    Port Linuxulator to IfAPI
    
    Reviewed by:    dchagin
    Sponsored by:   Juniper Networks, Inc.
    Differential Revision: https://reviews.freebsd.org/D38349
---
 sys/compat/linux/linux.c       | 104 +++++++++++++--------
 sys/compat/linux/linux.h       |   4 +-
 sys/compat/linux/linux_ioctl.c | 205 +++++++++++++++++++++++++----------------
 3 files changed, 195 insertions(+), 118 deletions(-)

diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c
index 4e435081b3b6..16aa731b20ff 100644
--- a/sys/compat/linux/linux.c
+++ b/sys/compat/linux/linux.c
@@ -241,6 +241,36 @@ bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
        }
 }
 
+struct ifname_linux_to_bsd_cb_s {
+       if_t ifp;
+       const char *lxname;
+       int unit;
+       int index;
+       bool is_lo;
+       bool is_eth;
+};
+
+static int
+ifname_linux_to_bsd_cb(if_t ifp, void *arg)
+{
+       struct ifname_linux_to_bsd_cb_s *cbs = arg;
+
+       /*
+        * Allow Linux programs to use FreeBSD names. Don't presume
+        * we never have an interface named "eth", so don't make
+        * the test optional based on is_eth.
+        */
+       cbs->ifp = ifp;
+       if (strncmp(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0)
+               return (-1);
+       if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->index++)
+               return (-1);
+       if (cbs->is_lo && IFP_IS_LOOP(ifp))
+               return (-1);
+       cbs->ifp = NULL;
+
+       return (0);
+}
 /*
  * Translate a Linux interface name to a FreeBSD interface name,
  * and return the associated ifnet structure
@@ -250,46 +280,33 @@ bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
 struct ifnet *
 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
 {
-       struct ifnet *ifp;
-       int len, unit;
+       struct ifname_linux_to_bsd_cb_s cbs = {};
+       int len;
        char *ep;
-       int index;
-       bool is_eth, is_lo;
 
+       cbs.lxname = lxname;
        for (len = 0; len < LINUX_IFNAMSIZ; ++len)
                if (!isalpha(lxname[len]) || lxname[len] == '\0')
                        break;
        if (len == 0 || len == LINUX_IFNAMSIZ)
                return (NULL);
        /* Linux loopback interface name is lo (not lo0) */
-       is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
-       unit = (int)strtoul(lxname + len, &ep, 10);
+       cbs.is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
+       cbs.unit = (int)strtoul(lxname + len, &ep, 10);
        if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) 
&&
-           is_lo == 0)
+           cbs.is_lo == 0)
                return (NULL);
-       index = 0;
-       is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
+       cbs.index = 0;
+       cbs.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
 
        CURVNET_SET(TD_TO_VNET(td));
        IFNET_RLOCK();
-       CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-               /*
-                * Allow Linux programs to use FreeBSD names. Don't presume
-                * we never have an interface named "eth", so don't make
-                * the test optional based on is_eth.
-                */
-               if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
-                       break;
-               if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
-                       break;
-               if (is_lo && IFP_IS_LOOP(ifp))
-                       break;
-       }
+       if_foreach(ifname_linux_to_bsd_cb, &cbs);
        IFNET_RUNLOCK();
        CURVNET_RESTORE();
-       if (ifp != NULL && bsdname != NULL)
-               strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
-       return (ifp);
+       if (cbs.ifp != NULL && bsdname != NULL)
+               strlcpy(bsdname, if_name(cbs.ifp), IFNAMSIZ);
+       return (cbs.ifp);
 }
 
 void
@@ -297,7 +314,7 @@ linux_ifflags(struct ifnet *ifp, short *flags)
 {
        unsigned short fl;
 
-       fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
+       fl = (if_getflags(ifp) | if_getdrvflags(ifp)) & 0xffff;
        *flags = 0;
        if (fl & IFF_UP)
                *flags |= LINUX_IFF_UP;
@@ -321,11 +338,28 @@ linux_ifflags(struct ifnet *ifp, short *flags)
                *flags |= LINUX_IFF_MULTICAST;
 }
 
+static u_int
+linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
+{
+       struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+       struct l_sockaddr *lsa = arg;
+
+       if (count > 0)
+               return (0);
+
+       if (sdl->sdl_type != IFT_ETHER)
+               return (0);
+
+       bzero(lsa, sizeof(*lsa));
+       lsa->sa_family = LINUX_ARPHRD_ETHER;
+       bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
+
+       return (1);
+}
+
 int
 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
 {
-       struct ifaddr *ifa;
-       struct sockaddr_dl *sdl;
 
        if (IFP_IS_LOOP(ifp)) {
                bzero(lsa, sizeof(*lsa));
@@ -336,16 +370,8 @@ linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
        if (!IFP_IS_ETH(ifp))
                return (ENOENT);
 
-       CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-               sdl = (struct sockaddr_dl*)ifa->ifa_addr;
-               if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
-                   (sdl->sdl_type == IFT_ETHER)) {
-                       bzero(lsa, sizeof(*lsa));
-                       lsa->sa_family = LINUX_ARPHRD_ETHER;
-                       bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
-                       return (0);
-               }
-       }
+       if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0)
+               return (0);
 
        return (ENOENT);
 }
@@ -732,5 +758,5 @@ bool
 linux_use_real_ifname(const struct ifnet *ifp)
 {
 
-       return (use_real_ifnames || !IFP_IS_ETH(ifp));
+       return (use_real_ifnames || !IFP_IS_ETH(__DECONST(if_t, ifp)));
 }
diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h
index 055d8e3b9cf6..e133c35010cf 100644
--- a/sys/compat/linux/linux.h
+++ b/sys/compat/linux/linux.h
@@ -287,8 +287,8 @@ struct l_statx {
 /*
  * Criteria for interface name translation
  */
-#define        IFP_IS_ETH(ifp)         ((ifp)->if_type == IFT_ETHER)
-#define        IFP_IS_LOOP(ifp)        ((ifp)->if_type == IFT_LOOP)
+#define        IFP_IS_ETH(ifp)         (if_gettype(ifp) == IFT_ETHER)
+#define        IFP_IS_LOOP(ifp)        (if_gettype(ifp) == IFT_LOOP)
 
 struct ifnet;
 
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index 2cb0e9ead23f..c70060b8bf5d 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -2087,46 +2087,138 @@ linux_ioctl_console(struct thread *td, struct 
linux_ioctl_args *args)
 /*
  * Implement the SIOCGIFNAME ioctl
  */
+struct linux_ioctl_ifname_cb_s {
+       struct l_ifreq ifr;
+       int index;
+       int ethno;
+};
+
+static int
+linux_ioctl_ifname_cb(if_t ifp, void *arg)
+{
+       struct linux_ioctl_ifname_cb_s *cbs = arg;
+       
+       if (cbs->ifr.ifr_ifindex == cbs->index) {
+               if (!linux_use_real_ifname(ifp))
+                       snprintf(cbs->ifr.ifr_name, LINUX_IFNAMSIZ,
+                           "eth%d", cbs->ethno);
+               else
+                       strlcpy(cbs->ifr.ifr_name, if_name(ifp),
+                           LINUX_IFNAMSIZ);
+               return (-1);
+       }
+       if (!linux_use_real_ifname(ifp))
+               cbs->ethno++;
+       cbs->index++;
+
+       return (0);
+}
 
 static int
 linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
 {
+       struct linux_ioctl_ifname_cb_s cbs;
        struct l_ifreq ifr;
-       struct ifnet *ifp;
-       int error, ethno, index;
+       int error;
 
-       error = copyin(uifr, &ifr, sizeof(ifr));
+       error = copyin(uifr, &cbs.ifr, sizeof(cbs.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;
-       CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-               if (ifr.ifr_ifindex == index) {
-                       if (!linux_use_real_ifname(ifp))
-                               snprintf(ifr.ifr_name, LINUX_IFNAMSIZ,
-                                   "eth%d", ethno);
-                       else
-                               strlcpy(ifr.ifr_name, ifp->if_xname,
-                                   LINUX_IFNAMSIZ);
-                       error = 0;
-                       break;
-               }
-               if (!linux_use_real_ifname(ifp))
-                       ethno++;
-               index++;
-       }
-       IFNET_RUNLOCK();
+       cbs.index = 1;  /* ifr.ifr_ifindex starts from 1 */
+       cbs.ethno = 0;
+       error = if_foreach(linux_ioctl_ifname_cb, &cbs);
+
        if (error == 0)
+               error = ENODEV;
+       IFNET_RUNLOCK();
+       if (error == -1)
                error = copyout(&ifr, uifr, sizeof(ifr));
        CURVNET_RESTORE();
 
        return (error);
 }
 
+static u_int
+linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
+{
+#ifdef COMPAT_LINUX32
+       struct l_ifconf *ifc;
+#else
+       struct ifconf *ifc;
+#endif
+       ifc = arg;
+       ifc->ifc_len += sizeof(struct l_ifreq);
+
+       return (1);
+}
+
+static int
+linux_ifconf_ifnet_cb(if_t ifp, void *arg)
+{
+       if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
+
+       return (0);
+}
+
+struct linux_ifconfig_ifaddr_cb2_s {
+       struct l_ifreq ifr;
+       struct sbuf *sb;
+       size_t max_len;
+       size_t valid_len;
+       int ethno;
+};
+
+static u_int
+linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
+{
+       struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+       struct sockaddr *sa = ifa->ifa_addr;
+
+       cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
+       memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
+           sizeof(cbs->ifr.ifr_addr.sa_data));
+       sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
+       cbs->max_len += sizeof(cbs->ifr);
+
+       if (sbuf_error(cbs->sb) == 0)
+               cbs->valid_len = sbuf_len(cbs->sb);
+
+       return (len);
+}
+
+static int
+linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
+{
+       struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+       int addrs = 0;
+
+       bzero(&cbs->ifr, sizeof(cbs->ifr));
+       if (IFP_IS_ETH(ifp))
+               snprintf(cbs->ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
+                   cbs->ethno++);
+       else
+               strlcpy(cbs->ifr.ifr_name, if_name(ifp), LINUX_IFNAMSIZ);
+
+       /* Walk the address list */
+       addrs = if_foreach_addr_type(ifp, AF_INET,
+           linux_ifconf_ifaddr_cb2, cbs);
+       if (sbuf_error(cbs->sb) == 0)
+               cbs->valid_len = sbuf_len(cbs->sb);
+       if (addrs == 0) {
+               bzero((caddr_t)&cbs->ifr.ifr_addr, sizeof(cbs->ifr.ifr_addr));
+               sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
+               cbs->max_len += sizeof(cbs->ifr);
+
+               if (sbuf_error(cbs->sb) == 0)
+                       cbs->valid_len = sbuf_len(cbs->sb);
+       }
+
+       return (0);
+}
+
 /*
  * Implement the SIOCGIFCONF ioctl
  */
@@ -2139,30 +2231,22 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
 #else
        struct ifconf ifc;
 #endif
-       struct l_ifreq ifr;
-       struct ifnet *ifp;
-       struct ifaddr *ifa;
+       struct linux_ifconfig_ifaddr_cb2_s cbs;
        struct sbuf *sb;
-       int error, ethno, full = 0, valid_len, max_len;
+       int error, full = 0;
 
        error = copyin(uifc, &ifc, sizeof(ifc));
        if (error != 0)
                return (error);
 
-       max_len = maxphys - 1;
+       cbs.max_len = maxphys - 1;
 
        CURVNET_SET(TD_TO_VNET(td));
        /* handle the 'request buffer size' case */
        if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
                ifc.ifc_len = 0;
                IFNET_RLOCK();
-               CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-                       CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-                               struct sockaddr *sa = ifa->ifa_addr;
-                               if (sa->sa_family == AF_INET)
-                                       ifc.ifc_len += sizeof(ifr);
-                       }
-               }
+               if_foreach(linux_ifconf_ifnet_cb, &ifc);
                IFNET_RUNLOCK();
                error = copyout(&ifc, uifc, sizeof(ifc));
                CURVNET_RESTORE();
@@ -2175,61 +2259,28 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
        }
 
 again:
+       cbs.ethno = 0;
        /* Keep track of eth interfaces */
-       ethno = 0;
-       if (ifc.ifc_len <= max_len) {
-               max_len = ifc.ifc_len;
+       if (ifc.ifc_len <= cbs.max_len) {
+               cbs.max_len = ifc.ifc_len;
                full = 1;
        }
-       sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
-       max_len = 0;
-       valid_len = 0;
+       sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
+       cbs.max_len = 0;
+       cbs.valid_len = 0;
+       cbs.sb = sb;
 
        /* Return all AF_INET addresses of all interfaces */
        IFNET_RLOCK();
-       CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-               int addrs = 0;
-
-               bzero(&ifr, sizeof(ifr));
-               if (IFP_IS_ETH(ifp))
-                       snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
-                           ethno++);
-               else
-                       strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
-
-               /* Walk the address list */
-               CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-                       struct sockaddr *sa = ifa->ifa_addr;
-
-                       if (sa->sa_family == AF_INET) {
-                               ifr.ifr_addr.sa_family = LINUX_AF_INET;
-                               memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
-                                   sizeof(ifr.ifr_addr.sa_data));
-                               sbuf_bcat(sb, &ifr, sizeof(ifr));
-                               max_len += sizeof(ifr);
-                               addrs++;
-                       }
-
-                       if (sbuf_error(sb) == 0)
-                               valid_len = sbuf_len(sb);
-               }
-               if (addrs == 0) {
-                       bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
-                       sbuf_bcat(sb, &ifr, sizeof(ifr));
-                       max_len += sizeof(ifr);
-
-                       if (sbuf_error(sb) == 0)
-                               valid_len = sbuf_len(sb);
-               }
-       }
+       if_foreach(linux_ifconf_ifnet_cb2, &cbs);
        IFNET_RUNLOCK();
 
-       if (valid_len != max_len && !full) {
+       if (cbs.valid_len != cbs.max_len && !full) {
                sbuf_delete(sb);
                goto again;
        }
 
-       ifc.ifc_len = valid_len;
+       ifc.ifc_len = cbs.valid_len;
        sbuf_finish(sb);
        error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
        if (error == 0)

Reply via email to