mirage/mirage-tcpip

non-server unikernels using DHCP have no obvious way to wait until network setup is complete

Closed this issue · 4 comments

Consider a purely client-side application which configures its network via DHCP (e.g., a unikernel that makes API requests of a remote server and manipulates a local data store according to their results).

The only obvious codepath for invoking DHCP setup (that I could find, anyway) is through STACKV4.listen stack, but this has a couple of problems for a client application:

  • listen stack recurses infinitely, so we can't bind our client thread to it
  • we don't actually want to run any listeners anyway

One could write an application which joined the listen thread and a client thread, but then the client thread begins its execution while listen is still setting up the network stack. In order to make only requests which have some chance of succeeding, the client thread has to know about (and block on) the state of the stack, which doesn't seem like a desirable solution to me.

Thanks,
Mindy

Hey, I stumbled upon the same issue some time ago -- mirage/mirage#232 (I work around it by using the `Socket backend, since doing a sleep didn't work out)

avsm commented

Yes indeed; we need to initialize the network stack before commencing the client connections.

Sorry for the commit spam.

As noted in the comments for the PR I just submitted, actually fixing this gets a little more complicated once the DHCP code is a little more fleshed out. DHCP should be a thread that continues for the life of the application, and probably needs to be joined with the application thread(s) when Mirage is building main.ml. For now, this fix moves the stack configuration (and therefore DHCP, when it's required) out of listen and into connect, so the user application doesn't see an unconfigured stack and isn't required to call listen.

avsm commented

Yes this fix is sound -- I just made a few simplifications (I hope) in #55.

In particular, Lwt.choose could schedule the threads in any order, so I chose to explicitly start the listen thread first and background it, and then start the configuration thread.

For interface shutdown to work, we'll need to stash this background thread somewhere and explicitly cancel it, but that's not particularly important at this stage, so I just marked it as a TODO (it's easier just to destroy the VM and recreate it than worry about shutting everything down).