aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2023-02-23 08:00:29 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2023-02-27 18:16:00 +0000
commitaeed04a32e459f2b7e0f78ca00ba257d7ac18123 (patch)
tree11bba6b733e173460650e4057180d7d4b1998cc1
parent8fd0f86abdfa8b98facb22649cb03545d0cf0df6 (diff)
downloadsrc-aeed04a32e459f2b7e0f78ca00ba257d7ac18123.tar.gz
src-aeed04a32e459f2b7e0f78ca00ba257d7ac18123.zip
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. Approved by: re (cperciva) Reviewed by: melifaro Differential Revision: https://reviews.freebsd.org/D38714 MFC after: 3 days X-MFC with: 32fdc75fe7 (cherry picked from commit 3ab3c9c29cf0e5df8dbbaaf2003456445534bad8) (cherry picked from commit a83551a52d1cfa8a756ef8dd298cab8042e27437)
-rw-r--r--sys/compat/linprocfs/linprocfs.c40
-rw-r--r--sys/compat/linux/linux.c87
-rw-r--r--sys/compat/linux/linux_common.h4
-rw-r--r--sys/compat/linux/linux_ioctl.c56
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
@@ -243,6 +243,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
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
@@ -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 cd89c16cad64..c9a04b51b4fa 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -2107,39 +2107,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);
}
/*
@@ -2149,6 +2127,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
@@ -2158,7 +2137,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)
@@ -2170,7 +2149,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;
@@ -2178,7 +2157,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);
@@ -2190,8 +2169,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;
@@ -2201,16 +2178,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) {
@@ -2237,7 +2211,7 @@ again:
valid_len = sbuf_len(sb);
}
}
- IFNET_RUNLOCK();
+ NET_EPOCH_EXIT(et);
if (valid_len != max_len && !full) {
sbuf_delete(sb);