firecracker-netns/cmd/main.go
RouxAntoine a9979519da feature: makefile target to build and use a custom kernel
Co-authored-by: RouxAntoine <antoinroux@hotmail.fr>
Co-committed-by: RouxAntoine <antoinroux@hotmail.fr>
2024-01-06 20:25:11 +00:00

163 lines
3.6 KiB
Go

//go:build linux
package main
// inspired by https://github.com/firecracker-microvm/firectl/blob/main/main.go#L64
import (
"antoine-roux.tk/projects/go/firecracker-netns/internal/netlink"
"antoine-roux.tk/projects/go/firecracker-netns/internal/netns"
"context"
"fmt"
"github.com/firecracker-microvm/firecracker-go-sdk"
"github.com/firecracker-microvm/firecracker-go-sdk/client/models"
"github.com/sirupsen/logrus"
"net"
"os"
"runtime"
)
func setupEnv() int {
log := logrus.New()
log.SetLevel(logrus.DebugLevel)
newNs, err := netns.New()
if err != nil {
fmt.Println("new ns error", err)
return 1
}
defer func(handle netns.NsHandle) {
err := handle.Close()
if err != nil {
fmt.Println("close ns error", err)
}
}(newNs)
defer func(ns netns.NsHandle) {
err := netns.Delete(ns)
if err != nil {
fmt.Println("delete ns error", err)
}
}(newNs)
vethPair, err := netlink.NewVirtualPairing(newNs, "wlp3s0")
if err != nil {
fmt.Println("new Veth error", err)
return 1
}
defer func(veth *netlink.PairLink) {
err = veth.DeleteVirtualPairing()
if err != nil {
fmt.Println("delete vethPair error", err)
}
}(vethPair)
err = netns.Set(newNs)
if err != nil {
fmt.Println("set guest ns error", err)
return 1
}
firstIpTapNetwork := net.IPv4(172, 16, 0, 1)
tapNetwork := net.IPNet{
IP: firstIpTapNetwork,
Mask: net.CIDRMask(30, 32),
}
tap, err := netlink.CreateTap(tapNetwork, vethPair.Guest.Link.Attrs().Name)
if err != nil {
fmt.Println("create tap in guest ns error", err)
return 1
}
defer func(tap *netlink.Tap) {
err := tap.DeleteTap()
if err != nil {
fmt.Println("delete tap error", err)
}
}(tap)
// Do something with the network namespace
interfaces, _ := net.Interfaces()
log.Debugf("Interfaces: %v\n", interfaces)
ctx := context.Background()
cancel, cancelFunc := context.WithCancel(ctx)
defer cancelFunc()
cpuCount := int64(4)
memorySize := int64(1024)
isSmt := true
socketPath := "/tmp/firecracker.socket"
cfg := firecracker.Config{
SocketPath: socketPath,
KernelImagePath: "./out/vmlinux",
LogPath: "./out/firecracker.log",
LogLevel: "Debug",
KernelArgs: "console=ttyS0 reboot=k panic=1 pci=off",
Drives: []models.Drive{
{
DriveID: firecracker.String("rootfs"),
PathOnHost: firecracker.String("./out/rootfs.ext4"),
IsReadOnly: firecracker.Bool(false),
IsRootDevice: firecracker.Bool(true),
},
},
NetworkInterfaces: firecracker.NetworkInterfaces{
firecracker.NetworkInterface{
StaticConfiguration: &firecracker.StaticNetworkConfiguration{
MacAddress: "06:00:AC:10:00:02",
HostDevName: tap.Link.Attrs().Name,
},
},
},
MachineCfg: models.MachineConfiguration{
VcpuCount: &cpuCount,
MemSizeMib: &memorySize,
Smt: &isSmt,
TrackDirtyPages: true,
},
}
firecrackerOpts := []firecracker.Opt{
firecracker.WithProcessRunner(
firecracker.VMCommandBuilder{}.
WithBin("firecracker").
WithSocketPath(socketPath).
Build(ctx),
),
firecracker.WithLogger(logrus.NewEntry(log)),
}
vm, err := firecracker.NewMachine(cancel, cfg, firecrackerOpts...)
if err != nil {
log.Errorln("create vm error", err)
return 1
}
defer os.Remove(cfg.SocketPath)
defer vm.StopVMM()
if err := vm.Start(ctx); err != nil {
log.Errorln("start vm error", err)
return 1
}
if err := vm.Wait(ctx); err != nil {
log.Errorln("wait vm error", err)
return 1
}
return 0
}
func main() {
// Lock the OS Thread, so we don't accidentally switch namespaces
runtime.LockOSThread()
defer runtime.UnlockOSThread()
os.Exit(setupEnv())
}