Sorry about delay. > On 20 May 2020, at 10:54, Martin Pieuchot <m...@openbsd.org> wrote: > > On 14/05/20(Thu) 15:53, Vitaliy Makkoveev wrote: >> Each `struct pppx_if' holds it's own `pipex_session' and this session is >> used directly within ifnet's related handlers pppx_if_start() and >> pppx_if_output(). > > I don't see a problem with keeping a reference on a pipex_session inside > the softc. Is there one? If so we might want to get rid of the descriptor > completely and always use a lookup function.
This diff was for my private question about if_detach(). I was wrong about if_detach(), so we can drop this diff :) Since we are going to move pipex(4) internals back, I tried to go in pppac(4) way. Pseudo-device logic, you pointed, is very similar. Also as pipex(4) was designed, session should be destroyed by pipex_ioctl() command PIPEXDSESSION. Corresponding function pipex_close_session() doesn’t kill session, but places it to queue, and this session will be deleted later if `pipexinq’ and `pipexoutq’ are empty. This was done to be sure there is no mbufs in queues with reference to this session. Real pipex(4) destruction is done by pipex_destroy_session(). pppac(4) hasn’t references to it’s sessions, so since I tried pppac(4) way did a step to remove reference in pppx(4) too. But in fact, pipex_iface_stop() uses direct pipex_destroy_session(). Also pppx_if_destroy() uses code copypasted from this function. It’s not clean for me why this is safe. Also we have disabled in-kernel timer for pppx(4) which wants to destroy session within pipex(4). > > Always doing lookups might adds an overhead, so it should be understood. pppac_start() does one search per mbuf within pipex_output(). In my diff ppppx_if_start() does one search per queue processing. pipex_output() uses radix tree, pipex_lookup_by_session_id() uses hash. > >> pppx_if_destroy() at first destroys `pipex_session' and calls >> if_deatch() which can cause context switch. Hypothetically, >> pppx_if_start() or pppx_if_output() can receive cpu at this moment and >> start to operate with already destroyed session. > > What do you mean with 'destroyed session'? If if_detach() sleeps the > session still exists, it is just no longer linked. I don't see what bug > exist in the scenario you're describing. In fact this code doesn't destroy session, but since it was copypasted from pipex_destroy_session() (without pool_put()) the meaning of this code is session destruction. May be the first step to deduplicate should be to move this code to new function pipex_session_unlink() and call it within pipex_destroy_session() and pppx_if_destroy(). Also we can introduce pipex_session_link() for pipex session creation. > >> I guess the order of `pppx_if' destruction in pppx_if_destroy() is >> right. If we call if_detach() before `pipex_session' destruction, after >> context switch caused by this if_detach() this session can be accessed >> from network stack, but it's own `ifnet' is already destoyed by >> if_detach(). > > if_detach() doesn't destroy anything. `ifp' is still valid, just no > longer referenced by the global data structures of the network stack. > > Concerning the order of operations I'd suggest being coherent with > other pseudo-devices. So look at vlan_clone_destroy(), > gre_clone_destroy(), etc for example. > >> Also pppx_add_session() has the same problem: newly created >> `pipex_session' can start to operate with half initilaized ifnet, so >> ifnet should be initialized before session creation. > > Currently the KERNEL_LOCK() is protecting all of that, but yes getting > the order of operations right helps. > >> Ifnet should be already exist outside corresponding `pipex_session' >> life time. And within ifnet's handlers we should be sure that session is >> valid. > > If we follow other pseudo-device logic we have indeed first a 'clone' > operation that creates and `ifp' then an ioctl like SIOCSVNETID which > links the descriptor to a global list. > > Your diff goes in this direction but misses some of the bits related to > the creation of interface like if_addgroup(), bpfattach(), etc. I'd > suggest you look at net/if_vlan.c :) > >> Diff below drops direct access of this `pipex_session' in ifnet's >> handlers. > > I don't see the point of this :/ > >> In pppx_if_start() we obtain corresponding session by >> pipex_lookup_by_session_id(). If pppx_if_start() was called in half of >> pppx_if_destroy(), pipex_lookup_by_session_id() will return NULL. >> Context switch can't be occured in pppx_if_start(). > > The IFF_RUNNING flag should be used to prevent this scenario. I'd > suggest imitating the logic in vlan_clone_destroy() in this case and > bring the interface down as a first step of the destroy process. pppx_if_start() already checks this flag, but pppx_if_destroy() doesn’t clear it. I will make diff for it. > > >> In pppx_if_output() the only ppp_id is requred. >> >> In pppx_add_session() if_attach() moved before `pipex_session' can be >> accessed by pipex(4) internals. > > As said above, please keep all the `ifp' initialization together. > >> Also this will be useful for future. We are going to move out pipex(4) >> related code from pppx(4) and after this diff it will be possible just >> remove all duplicating code from pppx_if_destroy() and >> pppx_add_session(). > > Please yes, remove the duplication before trying to address concurrency > issues. It will make review easier :) We stopped at `pppx_ifs_lk’ removal, so let’s continue but after [1] finished. 1. https://marc.info/?t=158998611500002&r=1&w=2