Use the new IfAPI interface and address iterators so the nfs driver
doesn't need direct access to the interface structures.
Details
- Reviewers
glebius melifaro - Group Reviewers
network - Commits
- rG0785c323f31c: Convert nfs bootp/diskless to use IfAPI
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
sys/nfs/bootp_subr.c | ||
---|---|---|
1541 | Isn't it just if_getifaddr(ifp) ? | |
sys/nfs/nfs_diskless.c | ||
157 | Nit: maybe a bit more descriptive name? It's a bit hard (at least for me) to understand what cbs is. | |
238 | Nit: maybe use C11 initializer here? |
sys/nfs/bootp_subr.c | ||
---|---|---|
1541 | I'm not sure. It's looking specifically for an IFT_ETHER type, would the if_addr always be an IFT_ETHER? | |
sys/nfs/nfs_diskless.c | ||
157 | We need to pass down 'ourdl', and pass back up 'ifp'. The API doesn't provide 'in' vs 'out'. | |
157 | It would be nice to have lambdas or blocks in the kernel, since most of these callback loops end up being rather trivial. |
sys/nfs/bootp_subr.c | ||
---|---|---|
1541 | if_attach() creates a new sdl, which is then assigned to if_addr. The data inside this sdl is derived from the if_type at the moment of attach (e.g. for everrything calling ether_ifattach() it will be IFT_ETHER). Additionally, I'm not sure if having AF_LINK address in the chain of addresses is the right thing to have. | |
sys/nfs/nfs_diskless.c | ||
157 | Sorry for not being clear - I meant the following: static u_int nfs_setup_diskless_ifa_cb(void *arg, struct sockaddr_dl *sdl, u_int count) { struct sockaddr_dl *outdl = arg; ... count = if_foreach_lladdr(ifp, nfs_setup_diskless_ifa_cb, cbs->ourdl); | |
157 | I'd love to have that. Not with C, unfortunately. |
I'm afraid I don't understand the diskless stuff related
to network configuration. I don't even have a diskless
setup to test with.
As such, I can't really be of any help.
Good luck with it, rick
sys/nfs/nfs_diskless.c | ||
---|---|---|
157 | Looked into the iterator part once again. Technically it can be simpler (just using if_next() with the iterator struct zeroed initially), but I see two benefits in this approach:
What do you think? Public KPI: struct if_iter { void *_ptr[4]; } void if_get_iter(struct if_iter *iter); struct ifnet *if_next(struct if_iter *iter); void if_free_iter(struct if_iter *iter); Usage: struct if_iter iter; if_get_iter(&iter); while ((struct ifnet *ifp = if_next(&iter)) != NULL) { ... } if_free_iter(&iter); Implementation: struct if_iter_private { struct ifnet *cur_ifp; struct ifnet *next_ifp; }; Static_assert(sizeof(struct if_iter_private) < sizeof(struct if_iter)); void if_get_iter(struct if_iter *_iter) { NET_EPOCH_ASSERT(); struct if_iter_private *iter = _iter; bzero(iter, sizeof(*iter)); iter->cur_ifp = CK_STAILQ_FIRST(&V_ifnet, if_link); if (iter->cur_ifp != NULL) iter->next_ifp = CK_STAILQ_NEXT(iter->cur_ifp, if_link); } struct ifnet * if_next(struct if_iter *_iter) { struct if_iter_private *iter = _iter; struct ifnet *ifp = iter->cur_ifp; iter->cur_ifp = iter->next_ifp; if (iter->cur_ifp != NULL) iter->next_ifp = CK_STAILQ_NEXT(iter->cur_ifp, if_link); return (ifp); } void if_free_iter(struct if_iter *iter __unused) { } |
@melifaro I like that approach overall, but I think it's nicer to keep it all local on the stack using an opaque context struct, then a user can do something like:
struct if_iter_t i; for (if_t ifp = if_iter_start(&i); ifp != NULL; ifp = if_next(i)) { do_something(ifp); }
This removes the if_free_iter() KPI you propose, until such a time comes that the iterator context blows out some set size (4 pointers as you had created).