unikernel: isolated host-only bridge networking (Phase 2)
When the mcp-br0 bridge exists, the agent runs unikernels on it instead of QEMU user-mode networking: each VM gets a TAP device on the bridge and a static 10.99.0.0/24 IP (baked into the Nanos image via ops RunConfig). With the host firewall dropping off-bridge VM traffic and no NAT, a VM can reach only the gateway -- making mc-proxy mediation mandatory by topology rather than convention. - runtime/qemu.go: bridge mode (createTAP/destroyTAP, IP allocator, deterministic MAC, static-IP ops config, VMAddr for proxy backends). - agent auto-enables bridge mode when /sys/class/net/mcp-br0 exists. Verified on straylight: uktest unikernel boots on mcp-br0 at 10.99.0.2, serves via the gateway, TAP enslaved to the bridge; bridge has no uplink and off-bridge forwarding is dropped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -59,12 +59,23 @@ func Run(cfg *config.AgentConfig, version string) error {
|
||||
// runtime = "unikernel" are placed by the master on KVM-capable nodes.
|
||||
var uk runtime.Runtime
|
||||
if unikernelSupported() {
|
||||
uk = &runtime.QEMU{
|
||||
qemu := &runtime.QEMU{
|
||||
ImageDir: filepath.Join(homeDir(cfg), "images"),
|
||||
StateDir: filepath.Join(homeDir(cfg), "vm"),
|
||||
HomeDir: homeDir(cfg),
|
||||
}
|
||||
logger.Info("unikernel runtime enabled (KVM detected)")
|
||||
// If the isolated host-only bridge exists, switch unikernels to
|
||||
// bridge networking (Phase 2: mandatory mediation). Otherwise they
|
||||
// use QEMU user-mode port forwards (Phase 1).
|
||||
if _, err := os.Stat("/sys/class/net/" + unikernelBridge); err == nil {
|
||||
qemu.Bridge = unikernelBridge
|
||||
qemu.Gateway = unikernelGateway
|
||||
qemu.SubnetPrefix = unikernelSubnetPrefix
|
||||
logger.Info("unikernel runtime enabled (KVM + isolated bridge)", "bridge", unikernelBridge)
|
||||
} else {
|
||||
logger.Info("unikernel runtime enabled (KVM, user-mode networking)")
|
||||
}
|
||||
uk = qemu
|
||||
}
|
||||
|
||||
mon := monitor.New(db, rt, cfg.Monitor, cfg.Agent.NodeName, logger)
|
||||
|
||||
@@ -10,6 +10,15 @@ import (
|
||||
"git.wntrmute.dev/mc/mcp/internal/runtime"
|
||||
)
|
||||
|
||||
// Isolated unikernel bridge parameters. The bridge (mcp-br0) is created by
|
||||
// the node's NixOS config; when present, the agent runs unikernels on it with
|
||||
// a host firewall confining each VM to reaching only the gateway (mc-proxy).
|
||||
const (
|
||||
unikernelBridge = "mcp-br0"
|
||||
unikernelGateway = "10.99.0.1"
|
||||
unikernelSubnetPrefix = "10.99.0"
|
||||
)
|
||||
|
||||
// unikernelSupported reports whether this node can run Nanos unikernels:
|
||||
// it needs KVM (/dev/kvm) and the `ops` toolchain on PATH.
|
||||
func unikernelSupported() bool {
|
||||
|
||||
Reference in New Issue
Block a user