linux(4): Migrate to IfAPI
Migrate linux and linprocfs to use the IfAPI interfaces instead of
direct ifnet accesses.
The code initially writed by jhibbits@, and adapted by me to 3ab3c9c2
.
Reviewed by: jhibbits
Differential Revision: https://reviews.freebsd.org/D38735
This commit is contained in:
parent
290f7f4a09
commit
6c5786fd37
@ -1478,12 +1478,49 @@ linprocfs_doprocmem(PFS_FILL_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Filler function for proc/net/dev
|
* Filler function for proc/net/dev
|
||||||
*/
|
*/
|
||||||
|
static int
|
||||||
|
linprocfs_donetdev_cb(if_t ifp, void *arg)
|
||||||
|
{
|
||||||
|
char ifname[LINUX_IFNAMSIZ];
|
||||||
|
struct sbuf *sb = arg;
|
||||||
|
|
||||||
|
if (ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname)) <= 0)
|
||||||
|
return (ENODEV);
|
||||||
|
|
||||||
|
sbuf_printf(sb, "%6.6s: ", ifname);
|
||||||
|
sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IBYTES),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IPACKETS),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IERRORS),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IQDROPS),
|
||||||
|
/* rx_missed_errors */
|
||||||
|
0UL, /* rx_fifo_errors */
|
||||||
|
0UL, /* rx_length_errors +
|
||||||
|
* rx_over_errors +
|
||||||
|
* rx_crc_errors +
|
||||||
|
* rx_frame_errors */
|
||||||
|
0UL, /* rx_compressed */
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IMCASTS));
|
||||||
|
/* XXX-BZ rx only? */
|
||||||
|
sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OBYTES),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OPACKETS),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OERRORS),
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OQDROPS),
|
||||||
|
0UL, /* tx_fifo_errors */
|
||||||
|
(uintmax_t)if_getcounter(ifp, IFCOUNTER_COLLISIONS),
|
||||||
|
0UL, /* tx_carrier_errors +
|
||||||
|
* tx_aborted_errors +
|
||||||
|
* tx_window_errors +
|
||||||
|
* tx_heartbeat_errors*/
|
||||||
|
0UL); /* tx_compressed */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
linprocfs_donetdev(PFS_FILL_ARGS)
|
linprocfs_donetdev(PFS_FILL_ARGS)
|
||||||
{
|
{
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
char ifname[16]; /* XXX LINUX_IFNAMSIZ */
|
|
||||||
struct ifnet *ifp;
|
|
||||||
|
|
||||||
sbuf_printf(sb, "%6s|%58s|%s\n"
|
sbuf_printf(sb, "%6s|%58s|%s\n"
|
||||||
"%6s|%58s|%58s\n",
|
"%6s|%58s|%58s\n",
|
||||||
@ -1494,36 +1531,7 @@ linprocfs_donetdev(PFS_FILL_ARGS)
|
|||||||
|
|
||||||
CURVNET_SET(TD_TO_VNET(curthread));
|
CURVNET_SET(TD_TO_VNET(curthread));
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
if_foreach(linprocfs_donetdev_cb, sb);
|
||||||
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),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
|
|
||||||
/* rx_missed_errors */
|
|
||||||
0UL, /* rx_fifo_errors */
|
|
||||||
0UL, /* rx_length_errors +
|
|
||||||
* rx_over_errors +
|
|
||||||
* rx_crc_errors +
|
|
||||||
* rx_frame_errors */
|
|
||||||
0UL, /* rx_compressed */
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
|
|
||||||
/* XXX-BZ rx only? */
|
|
||||||
sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
|
|
||||||
0UL, /* tx_fifo_errors */
|
|
||||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
|
|
||||||
0UL, /* tx_carrier_errors +
|
|
||||||
* tx_aborted_errors +
|
|
||||||
* tx_window_errors +
|
|
||||||
* tx_heartbeat_errors*/
|
|
||||||
0UL); /* tx_compressed */
|
|
||||||
}
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
CURVNET_RESTORE();
|
CURVNET_RESTORE();
|
||||||
|
|
||||||
|
@ -287,13 +287,37 @@ ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Translate a FreeBSD interface name to a Linux interface name,
|
* Translate a FreeBSD interface name to a Linux interface name,
|
||||||
* and return the number of bytes copied to lxname.
|
* and return the number of bytes copied to lxname, 0 if interface
|
||||||
|
* not found, -1 on error.
|
||||||
*/
|
*/
|
||||||
|
struct ifname_bsd_to_linux_ifp_cb_s {
|
||||||
|
struct ifnet *ifp;
|
||||||
|
int ethno;
|
||||||
|
char *lxname;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
ifname_bsd_to_linux_ifp_cb(if_t ifp, void *arg)
|
||||||
|
{
|
||||||
|
struct ifname_bsd_to_linux_ifp_cb_s *cbs = arg;
|
||||||
|
|
||||||
|
if (ifp == cbs->ifp)
|
||||||
|
return (snprintf(cbs->lxname, cbs->len, "eth%d", cbs->ethno));
|
||||||
|
if (IFP_IS_ETH(ifp))
|
||||||
|
cbs->ethno++;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
||||||
{
|
{
|
||||||
struct ifnet *ifscan;
|
struct ifname_bsd_to_linux_ifp_cb_s arg = {
|
||||||
int unit;
|
.ifp = ifp,
|
||||||
|
.ethno = 0,
|
||||||
|
.lxname = lxname,
|
||||||
|
.len = len,
|
||||||
|
};
|
||||||
|
|
||||||
NET_EPOCH_ASSERT();
|
NET_EPOCH_ASSERT();
|
||||||
|
|
||||||
@ -306,17 +330,10 @@ ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
|||||||
|
|
||||||
/* Short-circuit non ethernet interfaces. */
|
/* Short-circuit non ethernet interfaces. */
|
||||||
if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp))
|
if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp))
|
||||||
return (strlcpy(lxname, ifp->if_xname, len));
|
return (strlcpy(lxname, if_name(ifp), len));
|
||||||
|
|
||||||
/* Determine the (relative) unit number for ethernet interfaces. */
|
/* Determine the (relative) unit number for ethernet interfaces. */
|
||||||
unit = 0;
|
return (if_foreach(ifname_bsd_to_linux_ifp_cb, &arg));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -325,14 +342,53 @@ ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
|||||||
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
|
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
|
||||||
* can point to the same buffer.
|
* can point to the same buffer.
|
||||||
*/
|
*/
|
||||||
|
struct ifname_linux_to_bsd_cb_s {
|
||||||
|
bool is_lo;
|
||||||
|
bool is_eth;
|
||||||
|
int ethno;
|
||||||
|
int unit;
|
||||||
|
const char *lxname;
|
||||||
|
if_t ifp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
ifname_linux_to_bsd_cb(if_t ifp, void *arg)
|
||||||
|
{
|
||||||
|
struct ifname_linux_to_bsd_cb_s *cbs = arg;
|
||||||
|
|
||||||
|
NET_EPOCH_ASSERT();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0)
|
||||||
|
goto out;
|
||||||
|
if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->ethno)
|
||||||
|
goto out;
|
||||||
|
if (cbs->is_lo && IFP_IS_LOOP(ifp))
|
||||||
|
goto out;
|
||||||
|
if (IFP_IS_ETH(ifp))
|
||||||
|
cbs->ethno++;
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
out:
|
||||||
|
cbs->ifp = ifp;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
struct ifnet *
|
struct ifnet *
|
||||||
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp;
|
struct ifname_linux_to_bsd_cb_s arg = {
|
||||||
int len, unit;
|
.ethno = 0,
|
||||||
|
.lxname = lxname,
|
||||||
|
.ifp = NULL,
|
||||||
|
};
|
||||||
|
struct epoch_tracker et;
|
||||||
|
int len, ret;
|
||||||
char *ep;
|
char *ep;
|
||||||
int index;
|
|
||||||
bool is_eth, is_lo;
|
|
||||||
|
|
||||||
for (len = 0; len < LINUX_IFNAMSIZ; ++len)
|
for (len = 0; len < LINUX_IFNAMSIZ; ++len)
|
||||||
if (!isalpha(lxname[len]) || lxname[len] == '\0')
|
if (!isalpha(lxname[len]) || lxname[len] == '\0')
|
||||||
@ -343,34 +399,21 @@ ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
|||||||
* Linux loopback interface name is lo (not lo0),
|
* Linux loopback interface name is lo (not lo0),
|
||||||
* we translate lo to lo0, loX to loX.
|
* we translate lo to lo0, loX to loX.
|
||||||
*/
|
*/
|
||||||
is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
|
arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
|
||||||
unit = (int)strtoul(lxname + len, &ep, 10);
|
arg.unit = (int)strtoul(lxname + len, &ep, 10);
|
||||||
if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
|
if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
|
||||||
is_lo == 0)
|
arg.is_lo == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
index = 0;
|
arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
|
||||||
is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
|
|
||||||
|
|
||||||
CURVNET_SET(TD_TO_VNET(td));
|
CURVNET_SET(TD_TO_VNET(td));
|
||||||
IFNET_RLOCK();
|
NET_EPOCH_ENTER(et);
|
||||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
ret = if_foreach(ifname_linux_to_bsd_cb, &arg);
|
||||||
/*
|
NET_EPOCH_EXIT(et);
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
IFNET_RUNLOCK();
|
|
||||||
CURVNET_RESTORE();
|
CURVNET_RESTORE();
|
||||||
if (ifp != NULL && bsdname != NULL)
|
if (ret > 0 && arg.ifp != NULL && bsdname != NULL)
|
||||||
strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
|
strlcpy(bsdname, if_name(arg.ifp), IFNAMSIZ);
|
||||||
return (ifp);
|
return (arg.ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -378,7 +421,7 @@ linux_ifflags(struct ifnet *ifp, short *flags)
|
|||||||
{
|
{
|
||||||
unsigned short fl;
|
unsigned short fl;
|
||||||
|
|
||||||
fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
|
fl = (if_getflags(ifp) | if_getdrvflags(ifp)) & 0xffff;
|
||||||
*flags = 0;
|
*flags = 0;
|
||||||
if (fl & IFF_UP)
|
if (fl & IFF_UP)
|
||||||
*flags |= LINUX_IFF_UP;
|
*flags |= LINUX_IFF_UP;
|
||||||
@ -402,32 +445,35 @@ linux_ifflags(struct ifnet *ifp, short *flags)
|
|||||||
*flags |= LINUX_IFF_MULTICAST;
|
*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
|
int
|
||||||
linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
|
linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
|
||||||
{
|
{
|
||||||
struct ifaddr *ifa;
|
|
||||||
struct sockaddr_dl *sdl;
|
|
||||||
|
|
||||||
if (IFP_IS_LOOP(ifp)) {
|
if (IFP_IS_LOOP(ifp)) {
|
||||||
bzero(lsa, sizeof(*lsa));
|
bzero(lsa, sizeof(*lsa));
|
||||||
lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
|
lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IFP_IS_ETH(ifp))
|
if (!IFP_IS_ETH(ifp))
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
|
if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0)
|
||||||
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);
|
return (0);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,8 +287,8 @@ struct l_statx {
|
|||||||
/*
|
/*
|
||||||
* Criteria for interface name translation
|
* Criteria for interface name translation
|
||||||
*/
|
*/
|
||||||
#define IFP_IS_ETH(ifp) ((ifp)->if_type == IFT_ETHER)
|
#define IFP_IS_ETH(ifp) (if_gettype(ifp) == IFT_ETHER)
|
||||||
#define IFP_IS_LOOP(ifp) ((ifp)->if_type == IFT_LOOP)
|
#define IFP_IS_LOOP(ifp) (if_gettype(ifp) == IFT_LOOP)
|
||||||
|
|
||||||
struct ifnet;
|
struct ifnet;
|
||||||
|
|
||||||
|
@ -2108,40 +2108,91 @@ linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
|
|||||||
/*
|
/*
|
||||||
* Implement the SIOCGIFCONF ioctl
|
* Implement the SIOCGIFCONF ioctl
|
||||||
*/
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
|
||||||
|
{
|
||||||
|
struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
|
||||||
|
|
||||||
|
bzero(&cbs->ifr, sizeof(cbs->ifr));
|
||||||
|
ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
|
||||||
|
sizeof(cbs->ifr.ifr_name));
|
||||||
|
|
||||||
|
/* Walk the address list */
|
||||||
|
if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
linux_ifconf(struct thread *td, struct ifconf *uifc)
|
linux_ifconf(struct thread *td, struct ifconf *uifc)
|
||||||
{
|
{
|
||||||
|
struct linux_ifconfig_ifaddr_cb2_s cbs;
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
#ifdef COMPAT_LINUX32
|
#ifdef COMPAT_LINUX32
|
||||||
struct l_ifconf ifc;
|
struct l_ifconf ifc;
|
||||||
#else
|
#else
|
||||||
struct ifconf ifc;
|
struct ifconf ifc;
|
||||||
#endif
|
#endif
|
||||||
struct l_ifreq ifr;
|
|
||||||
struct ifnet *ifp;
|
|
||||||
struct ifaddr *ifa;
|
|
||||||
struct sbuf *sb;
|
struct sbuf *sb;
|
||||||
int error, full = 0, valid_len, max_len;
|
int error, full;
|
||||||
|
|
||||||
error = copyin(uifc, &ifc, sizeof(ifc));
|
error = copyin(uifc, &ifc, sizeof(ifc));
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
full = 0;
|
||||||
max_len = maxphys - 1;
|
cbs.max_len = maxphys - 1;
|
||||||
|
|
||||||
CURVNET_SET(TD_TO_VNET(td));
|
CURVNET_SET(TD_TO_VNET(td));
|
||||||
/* handle the 'request buffer size' case */
|
/* handle the 'request buffer size' case */
|
||||||
if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
|
if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
|
||||||
ifc.ifc_len = 0;
|
ifc.ifc_len = 0;
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
if_foreach(linux_ifconf_ifnet_cb, &ifc);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
error = copyout(&ifc, uifc, sizeof(ifc));
|
error = copyout(&ifc, uifc, sizeof(ifc));
|
||||||
CURVNET_RESTORE();
|
CURVNET_RESTORE();
|
||||||
@ -2154,56 +2205,25 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if (ifc.ifc_len <= max_len) {
|
if (ifc.ifc_len <= cbs.max_len) {
|
||||||
max_len = ifc.ifc_len;
|
cbs.max_len = ifc.ifc_len;
|
||||||
full = 1;
|
full = 1;
|
||||||
}
|
}
|
||||||
sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
|
cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
|
||||||
max_len = 0;
|
cbs.max_len = 0;
|
||||||
valid_len = 0;
|
cbs.valid_len = 0;
|
||||||
|
|
||||||
/* Return all AF_INET addresses of all interfaces */
|
/* Return all AF_INET addresses of all interfaces */
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
if_foreach(linux_ifconf_ifnet_cb2, &cbs);
|
||||||
int addrs = 0;
|
|
||||||
|
|
||||||
bzero(&ifr, sizeof(ifr));
|
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
|
|
||||||
if (valid_len != max_len && !full) {
|
if (cbs.valid_len != cbs.max_len && !full) {
|
||||||
sbuf_delete(sb);
|
sbuf_delete(sb);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
ifc.ifc_len = valid_len;
|
ifc.ifc_len = cbs.valid_len;
|
||||||
sbuf_finish(sb);
|
sbuf_finish(sb);
|
||||||
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
|
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user