Say, for example, I have a static website (like this blog) that I build in MirageOS. I want to make some changes to the TCP implementation against which the blog is built. In order to do that, I need to do all the following:
- figure out which module to change
- figure out which package provides that module
- get the source for that package and instruct the package manager to use it instead of the release
- make changes
- reinstall the package with your changes
- rebuild the unikernel completely
- see whether changes had the desired effect
Here’s a quick primer on how.
What am I changing?
If I want to change the TCP implementation (say, to try to fix this bug), I’m going to need to make an alteration to the code that’s provided to my unikernel fulfilling the TCP module type signature. I want to run my site as a unikernel on a Xen hypervisor, so I’ll build it with
mirage configure --xen, which decides which packages are most appropriate for providing the right functionality in the Xen context. Since I’m building with
--xen, the only option available for networking is the
direct stack (vs the
socket stack available when building with
What package provides that?
There are a few ways I can discover which package is providing the TCP implementation. I can look directly into the mirage front-end tool and find the relevant section for the TCP module, which currently looks like this:
1 2 3 4 5 6 7 8 9 10 11 12
method packages = Key.pure ["tcpip"], we can infer that the package providing this is
tcpip. Now that we know what package we need to look up, we can get some more information, including where to clone it from and where to report issues. Here’s an abbreviated look:
1 2 3 4 5 6 7 8 9 10
So now we know how to clone this package:
and we can make a new branch and commit some changes to it.
Pin that package in opam
Once we have a path or a git branch where we’ll make changes, we can instruct
opam to refer to that version of the package rather than the released one we were working with before. I generally use path-pinning for ease of hacking without making a lot of intermediate git commits, but others might prefer to point
opam at a branch.
The initial pin will cause
opam to reinstall the
tcpip package. Now if we rebuild our unikernel, we’ll use the pinned version:
1 2 3 4
We can verify that the unikernel has the behavior we desire to change after the pin (just in case someone’s already fixed the problem in the primary branch of the repository, but hasn’t yet made a release).
Make your changes
We’ll elide the details here, but it probably looks something like this:
1 2 3 4
Reinstall the package via opam
Since we made a change, we need to reinstall the package so that when we rebuild the unikernel, the changes will be reflected in the referenced installed package. We can do this with
If we’ve broken the build with our changes, the package may fail to reinstall. That’s OK; we can fix it and just try
opam reinstall tcpip again, and confirm that we want to install this package.
Rebuild the unikernel completely
We’ll redo the same steps we did when we initially pinned the package: clean the old state, reconfigure the unikernel, and rebuild it.
1 2 3 4
See whether the changes worked
If we have a simple test script for our unikernel (or our unikernel is a test script, like this ARP-testing unikernel), we can automatically confirm whether our changes fixed the problem. (We may even be able to see whether our changes broke anything else!)