Page MenuHomeFreeBSD

create netgraph ng_wormhole node type
Needs ReviewPublic

Authored by dave_freedave.net on May 7 2025, 6:44 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Jun 7, 7:06 AM
Unknown Object (File)
Sat, Jun 7, 3:42 AM
Unknown Object (File)
Fri, Jun 6, 10:51 PM
Unknown Object (File)
Fri, Jun 6, 8:11 PM
Unknown Object (File)
Fri, Jun 6, 1:58 PM
Unknown Object (File)
Fri, Jun 6, 10:00 AM
Unknown Object (File)
Thu, Jun 5, 8:55 AM
Unknown Object (File)
Thu, Jun 5, 4:32 AM

Details

Reviewers
glebius
kevans
kp
Group Reviewers
network
Jails
manpages
Summary

This is a new node type that allows netgraph nodes that are in different vnet(9)s to be connected. It absolutely does add an extra pair of function calls as data goes from one node to its wormhole, on to the next wormhole, and finally back out to another node.

But you will never pay more than that price as connecting two wormholes will cause collapse of one pair leaving behind only one pair.

For this to work you must mkpeer wormhole w evthorizon and separately open the wormhole into another jail. This creates the connected pair. The pair hold each other open, but until then they will shutdown when nothing is connected so you need to create with something like:

ngctl -f- << EOF
mkpeer wormhole w evthorizon
name .:w wh0
msg wh0: open “testjail"
EOF

This is intentionally minimalist and wormholes also have strict invariants:

  1. Both ends can NOT be in the same vnet(9), ever.
    • if they were you wouldn't need the wormhole!
  2. If you connect the evthorizon of two wormholes they collapse
    • As a consequence you can never have more than 2 extra function calls
  3. Wormholes can only be opened once.
  4. If either side of a wormhole is shutdown they both shutdown
    • As a consequence you don’t have to clean up on jail shutdown.
Test Plan

This assumes we already have D50241 available but I still consider this the "hard way":

jail -i -c name=demo host.hostname=demo.example.net vnet persist
kldload ng_eiface

echo -e "mkpeer eiface e ether\nname .:e ngeth0a" | ngctl -f -
echo -e "mkpeer eiface e ether\nname .:e ngeth0b" | ngctl -j demo -f -
ngctl mkpeer ngeth0a: wormhole ether evthorizon
ngctl msg ngeth0a:ether open '"demo"'

We still have one connection to make, but here we need to examine our current wormhole:

ngctl show ngeth0a:ether
  Name: <unnamed>       Type: wormhole        ID: 00000018   Num hooks: 2
  Local hook      Peer name       Peer type    Peer ID         Peer hook
  ----------      ---------       ---------    -------         ---------
  jid=1           <unnamed>       wormhole     0000000d        jid=0
  evthorizon      ngeth0a         eiface       0000000c        ether

That is intentional trickery in that we name the warp hook after the JIDs on either side. This matters because you need to know how to get to "the far side". In this case jail "demo" is JID 1 and the wormhole has ID 0000000d (these are unique per vnet!).

Ok assuming you adjust for your IDs you finally connect in the jail with:

ngctl -j 1 connect ngeth0b: [0000000d]: ether evthorizon

Just to be sure it actually works though lets do something trivial:

ifn=$(ngctl msg ngeth0a: getifname | sed '1d' | cut -d\" -f2)
ifconfig $ifn name ngeth0a
ifn=$(ngctl -j 1 msg ngeth0b: getifname | sed '1d' | cut -d\" -f2)
ifconfig -j 1 $ifn name ngeth0b

ifconfig ngeth0a inet 192.168.128.1/30 up
ifconfig -j 1 ngeth0b inet 192.168.128.2/30 up

ping 192.168.128.2
jexec demo ping 192.168.128.1

Lets clean all of that up now:

jail -r demo
ngctl shutdown ngeth0a:

Ok that is not showing off everything a wormhole can do but that is because I have a separate utility that makes using it easier
and I will add tests that use it once that review is up.

So there will be more! In particular we will be making this (in D50245):

vnet-wormhole-eiface.png (265×1 px, 23 KB)

But until then please feel free to start looking at the code, particularly interested in knowing if there is a better way than pulling in ng_rmnode. Also HK_COLLAPSE should probably be with other flags. That's the non-standard bit I definitely want more knowledgeable folks to look at but I appreciate everything being looked at as even if this never gets merged I use it!

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

Fix source file license per @ziaee (comment was in D50241).

share/man/man4/ng_wormhole.4
2

@ziaee I didn't (yet) change the man page license but can this shrink down too?

If it is allowed, is it just:

.\" Copyright (c) 2025 David Marker <dave@freedave.net>
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"

I saw that other man pages used the simplified license so I changed this to do the same.

Additionally I learned about mandoc -T lint and got the ng_wormhole.4 up to lint standards.

What is the use case for this?

share/man/man4/ng_wormhole.4
5

This is good.

In D50244#1153881, @imp wrote:

What is the use case for this?

I have an abandoned review D49158 I made because when you ifconfig ngethX vnet jailname to move an ng_eiface(4) into a jail it is covered by an ng_ether(4). I wrongly assumed this was a bug. Gleb was kind enough to walk me though a lot of the detail of why this is so (as well as suggesting a wormhole node).

But by covering the node we lose ability to really use it in its vnet(9). We can't place an ng_tee(4) in front of the ng_ether(4). Or rather you can, but you don't do it in the jail vnet.

I have a simple usage for using wormholes with basic jails on my github but that doesn't really get at where I'm planning to go. I want to spin up lots of jails for testing network partitions with RabbitMQ (among other things) using ng_pipe(4).

Using wormholes I could connect the main RMQ jail to a bridge on the system, create its own jail and now use sub-jails for the whole RMQ cluster. Bad ASCII art:

                               system | main RMQ cluster vnet
                               vnet   |
+-----------+     +-------------+     |     +-------------+      +-----------+
| ng_bridge |<--->| ng_wormhole | <---+---->| ng_wormhole |<---->| ng_bridge |
+--+--------+     +-------------+     |     +-------------+      +--+-----+--+
   |                                  |                            /       \
+--+--------+                         |                  +--------+--+   +--+----------+
| ng_ether  |                         |                  | ng_eiface |   | ng_wormhole |
+-----------+                         |                  +-----------+   +-------------+
                                      |                                         ^
                                      |                                         |
                                      |.........................................|....
                                      | instance n vnet                         |
                                      |                                         v
                                      |               +-----------+      +-------------+
                                      |               | ng_eiface |<---->| ng_wormhole |
                                      |               +-----------+      +-------------+

Imagine you stamp out many instances not just one. The more sprawling your jails become and the more frequently you create/destroy (especially from a template) the more useful this becomes. The cluster instance has to shutdown its sub-jails when it goes but that's as much as you need to track. The vnet(9) subsystem knows how to clean up all nodes left over and it does so after all processes are shutdown and nothing is using the netgraph nodes anyway.

That is my use case and planned use case (not yet using hierarchical jails). But really this completely opens up what you can do with netgraph in a jail and I suspect other uses could be found.

sys/netgraph/ng_wormhole.c
149

I already have a fix, but this only allows you to specify a jail by name not ID. I'll update with fix sometime tomorrow.

Allow a jail to be specified numerically to the "open" command.

sys/netgraph/ng_wormhole.c
31

If the module can't be used without VIMAGE/VNET, maybe we shouldn't compile it and the man page at all?

I mean add in the Makefile (sys/modules/netgraph/Makefile) something like this :

.if !defined(VIMAGE)
SUBDIR+= wormhole
.endif
sys/netgraph/ng_wormhole.c
31

Sorry:

.if defined(VIMAGE)
SUBDIR+= wormhole
.endif
sys/netgraph/ng_wormhole.h
17

Unfortunately, I don't have any better options yet, but it seems to me that the names are more from quantum physics than from network technologies. That is, from the names of the hooks, it will be completely unclear to an ordinary network engineer what and where to connect.

sys/netgraph/ng_wormhole.c
31

I knew there had to be a better way! Thank you.

I will definitely make this change, but give me some time as I'll need to test building without VIMAGE (something I never normally do).

sys/netgraph/ng_wormhole.h
17

The name wormhole was suggested in D49158. The node is about communication between prisons, I don't know of a term that means that and I don't want anything gang related. But I am absolutely willing to change it.

In the case of NG_WORMHOLE_WARP this should be in the C file as a user can't connect to this anyway. It is automatically connected upon "open" and it won't even show up in ngctl show wormhole: output (it will show up as jid=X to inform them what the wormhole connects to).

Just using VIMAGE in the Makefile didn't work but I noticed sys/modules/Makefile had an example that does work for wtap. I also stole the assert from sys/dev/wtap/if_wtap.c.

The man page is installed either way but that is the case with vnet(9) too so I assume its fine.

This actually makes things better for D50245 as it already exits if it can't load the module.

Marking changes addressed done. Just realized I still need to get "warp" and its define moved to C file.

remove NG_WORMHOLE_WARP from ng_wormhole.h as its not needed and in fact can't be referred to this way.

I'm calling this "done" but I'm still open to a name change.

I do understand the problem. I just think the name is a bit futuristic and not very descriptive for what it is doing.

In D50244#1156230, @bz wrote:

I do understand the problem. I just think the name is a bit futuristic and not very descriptive for what it is doing.

I'm using the metaphor of a vnet(9) being its own "network universe", where netgraph nodes get separate ID and name spaces etc. In that sense it is an unusual connection between the two vnet(9) "universes", and "wormhole" is meant to give you that clue.