The branch stable/13 has been updated by dchagin:

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

commit a83551a52d1cfa8a756ef8dd298cab8042e27437
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2023-02-23 08:00:29 +0000
Commit:     Dmitry Chagin <[email protected]>
CommitDate: 2023-02-26 08:10:44 +0000

    linux(4): Consolidate a FreeBSD interface names translation code
    
    We have some amount of interface names translation functions which are
    differs by bugs implementation. Consolidates it in a one place.
    
    Fixup loopback interface names translation and use ifnet methods and
    accessors, where possible.
    
    Reviewed by:            melifaro
    Differential Revision:  https://reviews.freebsd.org/D38714
    MFC after:              3 days
    X-MFC with:             32fdc75fe7
    
    (cherry picked from commit 3ab3c9c29cf0e5df8dbbaaf2003456445534bad8)
---
 sys/compat/linprocfs/linprocfs.c | 40 +++++-------------
 sys/compat/linux/linux.c         | 87 ++++++++++++++++++++++++++++++++++++++--
 sys/compat/linux/linux_common.h  |  4 ++
 sys/compat/linux/linux_ioctl.c   | 56 +++++++-------------------
 4 files changed, 113 insertions(+), 74 deletions(-)

diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index a93f8a1dbb8b..3aa01de9ce65 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -111,6 +111,7 @@ __FBSDID("$FreeBSD$");
 #endif /* __i386__ || __amd64__ */
 
 #include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_misc.h>
@@ -1474,36 +1475,13 @@ linprocfs_doprocmem(PFS_FILL_ARGS)
        return (error);
 }
 
-static int
-linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
-{
-       struct ifnet *ifscan;
-       int ethno;
-
-       IFNET_RLOCK_ASSERT();
-
-       /* Short-circuit non ethernet interfaces */
-       if (linux_use_real_ifname(ifp))
-               return (strlcpy(buffer, ifp->if_xname, buflen));
-
-       /* Determine the (relative) unit number for ethernet interfaces */
-       ethno = 0;
-       CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
-               if (ifscan == ifp)
-                       return (snprintf(buffer, buflen, "eth%d", ethno));
-               if (!linux_use_real_ifname(ifscan))
-                       ethno++;
-       }
-
-       return (0);
-}
-
 /*
  * Filler function for proc/net/dev
  */
 static int
 linprocfs_donetdev(PFS_FILL_ARGS)
 {
+       struct epoch_tracker et;
        char ifname[16]; /* XXX LINUX_IFNAMSIZ */
        struct ifnet *ifp;
 
@@ -1515,9 +1493,9 @@ linprocfs_donetdev(PFS_FILL_ARGS)
            "bytes    packets errs drop fifo colls carrier compressed");
 
        CURVNET_SET(TD_TO_VNET(curthread));
-       IFNET_RLOCK();
+       NET_EPOCH_ENTER(et);
        CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-               linux_ifname(ifp, ifname, sizeof ifname);
+               ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname));
                sbuf_printf(sb, "%6.6s: ", ifname);
                sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
                    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
@@ -1546,7 +1524,7 @@ linprocfs_donetdev(PFS_FILL_ARGS)
                                                         * tx_heartbeat_errors*/
                    0UL);                               /* tx_compressed */
        }
-       IFNET_RUNLOCK();
+       NET_EPOCH_EXIT(et);
        CURVNET_RESTORE();
 
        return (0);
@@ -1576,7 +1554,8 @@ linux_route_print(struct rtentry *rt, void *vw)
        /* select only first route in case of multipath */
        nh = nhop_select_func(rnd.rnd_nhop, 0);
 
-       linux_ifname(nh->nh_ifp, ifname, sizeof(ifname));
+       if (ifname_bsd_to_linux_ifp(nh->nh_ifp, ifname, sizeof(ifname)) <= 0)
+               return (ENODEV);
 
        gw = (nh->nh_flags & NHF_GATEWAY)
                ? nh->gw4_sa.sin_addr.s_addr : 0;
@@ -1605,6 +1584,7 @@ linux_route_print(struct rtentry *rt, void *vw)
 static int
 linprocfs_donetroute(PFS_FILL_ARGS)
 {
+       struct epoch_tracker et;
        struct walkarg w = {
                .sb = sb
        };
@@ -1615,9 +1595,9 @@ linprocfs_donetroute(PFS_FILL_ARGS)
                "\tWindow\tIRTT");
 
        CURVNET_SET(TD_TO_VNET(curthread));
-       IFNET_RLOCK();
+       NET_EPOCH_ENTER(et);
        rib_walk(fibnum, AF_INET, false, linux_route_print, &w);
-       IFNET_RUNLOCK();
+       NET_EPOCH_EXIT(et);
        CURVNET_RESTORE();
 
        return (0);
diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c
index bf0479b89588..41297d549c26 100644
--- a/sys/compat/linux/linux.c
+++ b/sys/compat/linux/linux.c
@@ -242,6 +242,84 @@ bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
        }
 }
 
+/*
+ * Translate a FreeBSD interface name to a Linux interface name
+ * by interface name, and return the number of bytes copied to lxname.
+ */
+int
+ifname_bsd_to_linux_name(const char *bsdname, char *lxname, size_t len)
+{
+       struct epoch_tracker et;
+       struct ifnet *ifp;
+       int ret;
+
+       ret = 0;
+       CURVNET_SET(TD_TO_VNET(curthread));
+       NET_EPOCH_ENTER(et);
+       ifp = ifunit(bsdname);
+       if (ifp != NULL)
+               ret = ifname_bsd_to_linux_ifp(ifp, lxname, len);
+       NET_EPOCH_EXIT(et);
+       CURVNET_RESTORE();
+       return (ret);
+}
+
+/*
+ * Translate a FreeBSD interface name to a Linux interface name
+ * by interface index, and return the number of bytes copied to lxname.
+ */
+int
+ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len)
+{
+       struct epoch_tracker et;
+       struct ifnet *ifp;
+       int ret;
+
+       ret = 0;
+       CURVNET_SET(TD_TO_VNET(curthread));
+       NET_EPOCH_ENTER(et);
+       ifp = ifnet_byindex(idx);
+       if (ifp != NULL)
+               ret = ifname_bsd_to_linux_ifp(ifp, lxname, len);
+       NET_EPOCH_EXIT(et);
+       CURVNET_RESTORE();
+       return (ret);
+}
+
+/*
+ * Translate a FreeBSD interface name to a Linux interface name,
+ * and return the number of bytes copied to lxname.
+ */
+int
+ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
+{
+       struct ifnet *ifscan;
+       int unit;
+
+       NET_EPOCH_ASSERT();
+
+       /*
+        * Linux loopback interface name is lo (not lo0),
+        * we translate lo to lo0, loX to loX.
+        */
+       if (IFP_IS_LOOP(ifp) && strncmp(ifp->if_xname, "lo0", IFNAMSIZ) == 0)
+               return (strlcpy(lxname, "lo", len));
+
+       /* Short-circuit non ethernet interfaces. */
+       if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp))
+               return (strlcpy(lxname, ifp->if_xname, len));
+
+       /* Determine the (relative) unit number for ethernet interfaces. */
+       unit = 0;
+       CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
+               if (ifscan == ifp)
+                       return (snprintf(lxname, len, "eth%d", unit));
+               if (IFP_IS_ETH(ifscan))
+                       unit++;
+       }
+       return (0);
+}
+
 /*
  * Translate a Linux interface name to a FreeBSD interface name,
  * and return the associated ifnet structure
@@ -262,8 +340,11 @@ ifname_linux_to_bsd(struct thread *td, const char *lxname, 
char *bsdname)
                        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);
+       /*
+        * Linux loopback interface name is lo (not lo0),
+        * we translate lo to lo0, loX to loX.
+        */
+       is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
        unit = (int)strtoul(lxname + len, &ep, 10);
        if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) 
&&
            is_lo == 0)
@@ -736,5 +817,5 @@ bool
 linux_use_real_ifname(const struct ifnet *ifp)
 {
 
-       return (use_real_ifnames || !IFP_IS_ETH(ifp));
+       return (use_real_ifnames);
 }
diff --git a/sys/compat/linux/linux_common.h b/sys/compat/linux/linux_common.h
index 0eb302bfcd17..9ebaff26b9ff 100644
--- a/sys/compat/linux/linux_common.h
+++ b/sys/compat/linux/linux_common.h
@@ -30,6 +30,10 @@
 #ifndef _LINUX_COMMON_H_
 #define _LINUX_COMMON_H_
 
+int    ifname_bsd_to_linux_ifp(struct ifnet *, char *, size_t);
+int    ifname_bsd_to_linux_idx(u_int, char *, size_t);
+int    ifname_bsd_to_linux_name(const char *, char *, size_t);
+
 struct ifnet   *ifname_linux_to_bsd(struct thread *td,
                    const char *lxname, char *bsdname);
 void           linux_ifflags(struct ifnet *ifp, short *flags);
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index 29edea547725..cd739522c496 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -2105,39 +2105,17 @@ static int
 linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
 {
        struct l_ifreq ifr;
-       struct ifnet *ifp;
-       int error, ethno, index;
+       int error, ret;
 
        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;
-       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();
-       if (error == 0)
-               error = copyout(&ifr, uifr, sizeof(ifr));
-       CURVNET_RESTORE();
-
-       return (error);
+       ret = ifname_bsd_to_linux_idx(ifr.ifr_ifindex, ifr.ifr_name,
+           LINUX_IFNAMSIZ);
+       if (ret > 0)
+               return (copyout(&ifr, uifr, sizeof(ifr)));
+       else
+               return (ENODEV);
 }
 
 /*
@@ -2147,6 +2125,7 @@ linux_ioctl_ifname(struct thread *td, struct l_ifreq 
*uifr)
 static int
 linux_ifconf(struct thread *td, struct ifconf *uifc)
 {
+       struct epoch_tracker et;
 #ifdef COMPAT_LINUX32
        struct l_ifconf ifc;
 #else
@@ -2156,7 +2135,7 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
        struct ifnet *ifp;
        struct ifaddr *ifa;
        struct sbuf *sb;
-       int error, ethno, full = 0, valid_len, max_len;
+       int error, full = 0, valid_len, max_len;
 
        error = copyin(uifc, &ifc, sizeof(ifc));
        if (error != 0)
@@ -2168,7 +2147,7 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
        /* handle the 'request buffer size' case */
        if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
                ifc.ifc_len = 0;
-               IFNET_RLOCK();
+               NET_EPOCH_ENTER(et);
                CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
                        CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
                                struct sockaddr *sa = ifa->ifa_addr;
@@ -2176,7 +2155,7 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
                                        ifc.ifc_len += sizeof(ifr);
                        }
                }
-               IFNET_RUNLOCK();
+               NET_EPOCH_EXIT(et);
                error = copyout(&ifc, uifc, sizeof(ifc));
                CURVNET_RESTORE();
                return (error);
@@ -2188,8 +2167,6 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
        }
 
 again:
-       /* Keep track of eth interfaces */
-       ethno = 0;
        if (ifc.ifc_len <= max_len) {
                max_len = ifc.ifc_len;
                full = 1;
@@ -2199,16 +2176,13 @@ again:
        valid_len = 0;
 
        /* Return all AF_INET addresses of all interfaces */
-       IFNET_RLOCK();
+       NET_EPOCH_ENTER(et);
        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);
+               ifname_bsd_to_linux_ifp(ifp, ifr.ifr_name,
+                   sizeof(ifr.ifr_name));
 
                /* Walk the address list */
                CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
@@ -2235,7 +2209,7 @@ again:
                                valid_len = sbuf_len(sb);
                }
        }
-       IFNET_RUNLOCK();
+       NET_EPOCH_EXIT(et);
 
        if (valid_len != max_len && !full) {
                sbuf_delete(sb);

Reply via email to