Convert nfs bootp/diskless to use IfAPI

Use the new IfAPI interface and address iterators so the nfs driver
doesn't need direct access to the interface structures.

Sponsored by:	Juniper Networks, Inc.
Differential Revision: https://reviews.freebsd.org/D38962
This commit is contained in:
Justin Hibbits 2023-02-07 14:37:03 -05:00
parent 4db5958a06
commit 0785c323f3
2 changed files with 86 additions and 73 deletions

View file

@ -137,7 +137,7 @@ struct bootpc_ifcontext {
} _req; } _req;
#define ireq _req._ifreq #define ireq _req._ifreq
#define iareq _req._in_alias_req #define iareq _req._in_alias_req
struct ifnet *ifp; if_t ifp;
struct sockaddr_dl *sdl; struct sockaddr_dl *sdl;
struct sockaddr_in myaddr; struct sockaddr_in myaddr;
struct sockaddr_in netmask; struct sockaddr_in netmask;
@ -263,7 +263,6 @@ static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
unsigned char *start, int len, int tag); unsigned char *start, int len, int tag);
#ifdef BOOTP_DEBUG #ifdef BOOTP_DEBUG
void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa);
void bootpboot_p_iflist(void); void bootpboot_p_iflist(void);
#endif #endif
@ -295,38 +294,35 @@ static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
*/ */
#ifdef BOOTP_DEBUG #ifdef BOOTP_DEBUG
void static u_int
bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa) bootpboot_p_ifa(void *ifp, struct ifaddr *ifa, u_int count __unused)
{ {
printf("%s flags %x, addr ", printf("%s flags %x, addr ",
ifp->if_xname, ifp->if_flags); if_name(ifp), if_getflags(ifp));
print_sin_addr((struct sockaddr_in *) ifa->ifa_addr); print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
printf(", broadcast "); printf(", broadcast ");
print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr); print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
printf(", netmask "); printf(", netmask ");
print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask); print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
printf("\n"); printf("\n");
return (0);
} }
void void
bootpboot_p_iflist(void) bootpboot_p_iflist(void)
{ {
struct ifnet *ifp; struct epoch_tracker et;
struct ifaddr *ifa; struct if_iter iter;
if_t ifp;
printf("Interface list:\n"); printf("Interface list:\n");
IFNET_RLOCK(); NET_EPOCH_ENTER(et);
for (ifp = CK_STAILQ_FIRST(&V_ifnet); for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter))
ifp != NULL; if_foreach_addr_type(ifp, AF_INET, bootpboot_p_ifa, ifp);
ifp = CK_STAILQ_NEXT(ifp, if_link)) { if_iter_finish(&iter);
for (ifa = CK_STAILQ_FIRST(&ifp->if_addrhead); NET_EPOCH_EXIT(et);
ifa != NULL;
ifa = CK_STAILQ_NEXT(ifa, ifa_link))
if (ifa->ifa_addr->sa_family == AF_INET)
bootpboot_p_if(ifp, ifa);
}
IFNET_RUNLOCK();
} }
#endif /* defined(BOOTP_DEBUG) */ #endif /* defined(BOOTP_DEBUG) */
@ -1498,14 +1494,31 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
} }
} }
static u_int
bootpc_init_ifa_cb(void *arg, struct ifaddr *ifa, u_int count)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (count != 0)
return (0);
if (sdl->sdl_type != IFT_ETHER)
return (0);
*(struct sockaddr_dl **)arg = sdl;
return (1);
}
void void
bootpc_init(void) bootpc_init(void)
{ {
struct epoch_tracker et;
struct bootpc_ifcontext *ifctx = NULL; /* Interface BOOTP contexts */ struct bootpc_ifcontext *ifctx = NULL; /* Interface BOOTP contexts */
struct bootpc_globalcontext *gctx; /* Global BOOTP context */ struct bootpc_globalcontext *gctx; /* Global BOOTP context */
struct ifnet *ifp;
struct sockaddr_dl *sdl; struct sockaddr_dl *sdl;
struct ifaddr *ifa; struct if_iter iter;
if_t ifp;
int error; int error;
#ifndef BOOTP_WIRED_TO #ifndef BOOTP_WIRED_TO
int ifcnt; int ifcnt;
@ -1573,22 +1586,15 @@ bootpc_init(void)
* attaches and wins the race, it won't be eligible for bootp. * attaches and wins the race, it won't be eligible for bootp.
*/ */
ifcnt = 0; ifcnt = 0;
IFNET_RLOCK(); NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { for (if_t ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
if ((ifp->if_flags & if ((if_getflags(ifp) &
(IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) ==
IFF_BROADCAST) IFF_BROADCAST)
continue; ifcnt++;
switch (ifp->if_alloctype) {
case IFT_ETHER:
break;
default:
continue;
}
ifcnt++;
} }
if_iter_finish(&iter);
IFNET_RUNLOCK(); NET_EPOCH_EXIT(et);
if (ifcnt == 0) { if (ifcnt == 0) {
printf("WARNING: BOOTP found no eligible network interfaces, skipping!\n"); printf("WARNING: BOOTP found no eligible network interfaces, skipping!\n");
goto out; goto out;
@ -1600,37 +1606,32 @@ bootpc_init(void)
retry: retry:
ifctx = STAILQ_FIRST(&gctx->interfaces); ifctx = STAILQ_FIRST(&gctx->interfaces);
IFNET_RLOCK(); NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
if (ifctx == NULL) if (ifctx == NULL)
break; break;
#ifdef BOOTP_WIRED_TO #ifdef BOOTP_WIRED_TO
if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0) if (strcmp(if_name(ifp), __XSTRING(BOOTP_WIRED_TO)) != 0)
continue; continue;
#else #else
if ((ifp->if_flags & if ((if_getflags(ifp) &
(IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
IFF_BROADCAST) IFF_BROADCAST)
continue; break;
switch (ifp->if_alloctype) { switch (if_getalloctype(ifp)) {
case IFT_ETHER: case IFT_ETHER:
break; break;
default: default:
continue; continue;
} }
#endif #endif
strlcpy(ifctx->ireq.ifr_name, ifp->if_xname, strlcpy(ifctx->ireq.ifr_name, if_name(ifp),
sizeof(ifctx->ireq.ifr_name)); sizeof(ifctx->ireq.ifr_name));
ifctx->ifp = ifp; ifctx->ifp = ifp;
/* Get HW address */ /* Get HW address */
sdl = NULL; sdl = NULL;
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if_foreach_addr_type(ifp, AF_LINK, bootpc_init_ifa_cb, &sdl);
if (ifa->ifa_addr->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl->sdl_type == IFT_ETHER)
break;
}
if (sdl == NULL) if (sdl == NULL)
panic("bootpc: Unable to find HW address for %s", panic("bootpc: Unable to find HW address for %s",
ifctx->ireq.ifr_name); ifctx->ireq.ifr_name);
@ -1638,7 +1639,8 @@ bootpc_init(void)
ifctx = STAILQ_NEXT(ifctx, next); ifctx = STAILQ_NEXT(ifctx, next);
} }
IFNET_RUNLOCK(); if_iter_finish(&iter);
NET_EPOCH_EXIT(et);
CURVNET_RESTORE(); CURVNET_RESTORE();
if (STAILQ_EMPTY(&gctx->interfaces) || if (STAILQ_EMPTY(&gctx->interfaces) ||
@ -1702,7 +1704,7 @@ bootpc_init(void)
if (gctx->gotrootpath != 0) { if (gctx->gotrootpath != 0) {
struct epoch_tracker et; struct epoch_tracker et;
kern_setenv("boot.netif.name", ifctx->ifp->if_xname); kern_setenv("boot.netif.name", if_name(ifctx->ifp));
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
bootpc_add_default_route(ifctx); bootpc_add_default_route(ifctx);

View file

@ -146,6 +146,19 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd)
free(opts, M_TEMP); free(opts, M_TEMP);
} }
static u_int
nfs_setup_diskless_ifa_cb(void *arg, struct sockaddr_dl *sdl, u_int count)
{
struct sockaddr_dl *ourdl = arg;
if ((sdl->sdl_type == ourdl->sdl_type) &&
(sdl->sdl_alen == ourdl->sdl_alen) &&
!bcmp(LLADDR(sdl), LLADDR(ourdl), sdl->sdl_alen))
return (1);
return (0);
}
/* /*
* Populate the essential fields in the nfsv3_diskless structure. * Populate the essential fields in the nfsv3_diskless structure.
* *
@ -166,16 +179,18 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd)
void void
nfs_setup_diskless(void) nfs_setup_diskless(void)
{ {
struct epoch_tracker et;
struct if_iter iter;
struct nfs_diskless *nd = &nfs_diskless; struct nfs_diskless *nd = &nfs_diskless;
struct nfsv3_diskless *nd3 = &nfsv3_diskless; struct nfsv3_diskless *nd3 = &nfsv3_diskless;
struct ifnet *ifp; if_t ifp;
struct ifaddr *ifa; struct sockaddr_dl ourdl;
struct sockaddr_dl *sdl, ourdl;
struct sockaddr_in myaddr, netmask; struct sockaddr_in myaddr, netmask;
char *cp; char *cp;
int cnt, fhlen, is_nfsv3; int cnt, fhlen, is_nfsv3;
uint32_t len; uint32_t len;
time_t timeout_at; time_t timeout_at;
u_int count;
if (nfs_diskless_valid != 0) if (nfs_diskless_valid != 0)
return; return;
@ -219,29 +234,25 @@ nfs_setup_diskless(void)
printf("nfs_diskless: no hardware address\n"); printf("nfs_diskless: no hardware address\n");
return; return;
} }
ifa = NULL;
timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS; timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS;
retry: retry:
CURVNET_SET(TD_TO_VNET(curthread)); CURVNET_SET(TD_TO_VNET(curthread));
IFNET_RLOCK(); NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
if (ifa->ifa_addr->sa_family == AF_LINK) { count = if_foreach_lladdr(ifp, nfs_setup_diskless_ifa_cb, &ourdl);
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if ((sdl->sdl_type == ourdl.sdl_type) && if (count > 0)
(sdl->sdl_alen == ourdl.sdl_alen) && break;
!bcmp(LLADDR(sdl),
LLADDR(&ourdl),
sdl->sdl_alen)) {
IFNET_RUNLOCK();
CURVNET_RESTORE();
goto match_done;
}
}
}
} }
IFNET_RUNLOCK(); if_iter_finish(&iter);
NET_EPOCH_EXIT(et);
CURVNET_RESTORE(); CURVNET_RESTORE();
if (cnt > 0) {
goto match_done;
}
if (time_uptime < timeout_at) { if (time_uptime < timeout_at) {
pause("nfssdl", hz / 5); pause("nfssdl", hz / 5);
goto retry; goto retry;
@ -249,9 +260,9 @@ nfs_setup_diskless(void)
printf("nfs_diskless: no interface\n"); printf("nfs_diskless: no interface\n");
return; /* no matching interface */ return; /* no matching interface */
match_done: match_done:
kern_setenv("boot.netif.name", ifp->if_xname); kern_setenv("boot.netif.name", if_name(ifp));
if (is_nfsv3 != 0) { if (is_nfsv3 != 0) {
strlcpy(nd3->myif.ifra_name, ifp->if_xname, strlcpy(nd3->myif.ifra_name, if_name(ifp),
sizeof(nd3->myif.ifra_name)); sizeof(nd3->myif.ifra_name));
/* set up gateway */ /* set up gateway */
@ -290,7 +301,7 @@ nfs_setup_diskless(void)
nfs_diskless_valid = 3; nfs_diskless_valid = 3;
} else { } else {
strlcpy(nd->myif.ifra_name, ifp->if_xname, strlcpy(nd->myif.ifra_name, if_name(ifp),
sizeof(nd->myif.ifra_name)); sizeof(nd->myif.ifra_name));
/* set up gateway */ /* set up gateway */