Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Commit

Permalink
Merge pull request #14 from rancher-sandbox/wsl-integration
Browse files Browse the repository at this point in the history
Create a veth pair to enable the network connectivity between default and RD namespace
  • Loading branch information
mook-as authored Oct 17, 2023
2 parents 61a006f + 3d9bf11 commit 648cb51
Showing 1 changed file with 135 additions and 33 deletions.
168 changes: 135 additions & 33 deletions cmd/network/setup_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import (
"fmt"
"io"
"io/fs"
"net"
"os"
"os/exec"
"strconv"

"github.com/linuxkit/virtsock/pkg/vsock"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"

"github.com/rancher-sandbox/rancher-desktop-networking/pkg/config"
Expand All @@ -43,33 +45,22 @@ var (
)

const (
nsenter = "/usr/bin/nsenter"
unshare = "/usr/bin/unshare"
vsockHandshakePort = 6669
vsockDialPort = 6656
defaultTapDevice = "eth0"
nsenter = "/usr/bin/nsenter"
unshare = "/usr/bin/unshare"
vsockHandshakePort = 6669
vsockDialPort = 6656
defaultTapDevice = "eth0"
defaultNSVeth = "veth-rd0"
rancherDesktopNSVeth = "veth-rd1"
defaultNamespacePID = 1
cidrOnes = 24
cidrBits = 32
)

func main() {
flag.BoolVar(&debug, "debug", false, "enable additional debugging")
flag.StringVar(&tapIface, "tap-interface", defaultTapDevice, "tap interface name, eg. eth0, eth1")
flag.StringVar(&subnet, "subnet", config.DefaultSubnet,
fmt.Sprintf("Subnet range with CIDR suffix that is associated to the tap interface, e,g: %s", config.DefaultSubnet))
flag.StringVar(&tapDeviceMacAddr, "tap-mac-address", config.TapDeviceMacAddr,
"MAC address that is associated to the tap interface")
flag.StringVar(&vmSwitchPath, "vm-switch-path", "", "the path to the vm-switch binary that will run in a new namespace")
flag.StringVar(&vmSwitchLogFile, "vm-switch-logfile", "", "path to the logfile for vm-switch process")
flag.StringVar(&unshareArg, "unshare-arg", "", "the command argument to pass to the unshare program")
flag.StringVar(&logFile, "logfile", "/var/log/network-setup.log", "path to the logfile for network setup process")
flag.Parse()

if err := log.SetOutputFile(logFile, logrus.StandardLogger()); err != nil {
logrus.Fatalf("setting logger's output file failed: %v", err)
}
initializeFlags()

if debug {
logrus.SetLevel(logrus.DebugLevel)
}
setupLogging(logFile)

if vmSwitchPath == "" {
logrus.Fatal("path to the vm-switch process must be provided")
Expand All @@ -89,6 +80,11 @@ func main() {
}
logrus.Debugf("successful connection to host on CID: %v and Port: %d: connection: %+v", vsock.CIDHost, vsockDialPort, vsockConn)

originNS, err := netns.Get()
if err != nil {
logrus.Errorf("failed getting a handle to the current namespace: %v", err)
}

// setup network namespace
ns, err := configureNamespace()
if err != nil {
Expand All @@ -99,6 +95,85 @@ func main() {
logrus.Fatal(err)
}

connFile, err := vsockConn.File()
if err != nil {
logrus.Fatal(err)
}

vmSwitchCmd := configureVMSwitch(ns,
vmSwitchLogFile,
vmSwitchPath,
tapIface,
subnet,
tapDeviceMacAddr,
connFile)

if err := vmSwitchCmd.Start(); err != nil {
logrus.Fatalf("could not start the vm-switch process: %v", err)
}
logrus.Infof("successfully started the vm-switch running with a PID: %v", vmSwitchCmd.Process.Pid)

err = createVethPair(defaultNamespacePID,
vmSwitchCmd.Process.Pid,
defaultNSVeth,
rancherDesktopNSVeth)
if err != nil {
logrus.Fatal(err)
}

if err := configureVethPair(rancherDesktopNSVeth, "192.168.1.2"); err != nil {
logrus.Fatalf("failed setting up veth: %s for rancher desktop namespace: %v", rancherDesktopNSVeth, err)
}

// switch back to the original namespace to configure veth0
if err := netns.Set(originNS); err != nil {
logrus.Fatal(err)
}
if err := configureVethPair(defaultNSVeth, "192.168.1.1"); err != nil {
logrus.Fatalf("failed setting up veth: %s for rancher desktop namespace: %v", rancherDesktopNSVeth, err)
}

if err := originNS.Close(); err != nil {
logrus.Error(err)
}

if err := vmSwitchCmd.Wait(); err != nil {
logrus.Errorf("vm-switch exited with error: %v", err)
}
}

func initializeFlags() {
flag.BoolVar(&debug, "debug", false, "enable additional debugging")
flag.StringVar(&tapIface, "tap-interface", defaultTapDevice, "tap interface name, eg. eth0, eth1")
flag.StringVar(&subnet, "subnet", config.DefaultSubnet,
fmt.Sprintf("Subnet range with CIDR suffix that is associated to the tap interface, e,g: %s", config.DefaultSubnet))
flag.StringVar(&tapDeviceMacAddr, "tap-mac-address", config.TapDeviceMacAddr,
"MAC address that is associated to the tap interface")
flag.StringVar(&vmSwitchPath, "vm-switch-path", "", "the path to the vm-switch binary that will run in a new namespace")
flag.StringVar(&vmSwitchLogFile, "vm-switch-logfile", "", "path to the logfile for vm-switch process")
flag.StringVar(&unshareArg, "unshare-arg", "", "the command argument to pass to the unshare program")
flag.StringVar(&logFile, "logfile", "/var/log/network-setup.log", "path to the logfile for network setup process")
flag.Parse()
}

func setupLogging(logFile string) {
if err := log.SetOutputFile(logFile, logrus.StandardLogger()); err != nil {
logrus.Fatalf("setting logger's output file failed: %v", err)
}

if debug {
logrus.SetLevel(logrus.DebugLevel)
}
}

func configureVMSwitch(
ns netns.NsHandle,
vmSwitchLogFile,
vmSwitchPath,
tapIface,
subnet,
tapDevMacAddr string,
connFile *os.File) *exec.Cmd {
// Start the vm-switch process in the new namespace; we do
// this as the golang runtime can switch threads at will, so it
// is safer to have a whole process in a consistent namespace.
Expand All @@ -111,7 +186,7 @@ func main() {
"-subnet",
subnet,
"-tap-mac-address",
tapDeviceMacAddr,
tapDevMacAddr,
}
if vmSwitchLogFile != "" {
args = append(args, "-logfile", vmSwitchLogFile)
Expand All @@ -121,21 +196,48 @@ func main() {
}
vmSwitchCmd := exec.Command(nsenter, args...)

connFile, err := vsockConn.File()
if err != nil {
logrus.Fatal(err)
}
// pass in the vsock connection as a FD to the
// vm-switch process in the newely created namespace
vmSwitchCmd.ExtraFiles = []*os.File{connFile}
if err := vmSwitchCmd.Start(); err != nil {
logrus.Fatalf("could not start the vm-switch process: %v", err)
return vmSwitchCmd
}

func createVethPair(defaultNsPid, peerNsPid int, defaultNSVeth, rancherDesktopNSVeth string) error {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: defaultNSVeth,
Namespace: netlink.NsPid(defaultNsPid),
},
PeerName: rancherDesktopNSVeth,
PeerNamespace: netlink.NsPid(peerNsPid),
}
logrus.Infof("successfully started the vm-switch running with a PID: %v", vmSwitchCmd.Process.Pid)
if err := netlink.LinkAdd(veth); err != nil {
return err
}
logrus.Infof("created veth pair %s and %s", defaultNSVeth, rancherDesktopNSVeth)
return nil
}

if err := vmSwitchCmd.Wait(); err != nil {
logrus.Errorf("vm-switch exited with error: %v", err)
func configureVethPair(vethName, ipAddr string) error {
veth, err := netlink.LinkByName(vethName)
if err != nil {
return err
}

vethIP := net.IPNet{
IP: net.ParseIP(ipAddr),
Mask: net.CIDRMask(cidrOnes, cidrBits),
}

addr := &netlink.Addr{IPNet: &vethIP, Label: ""}
if err := netlink.AddrAdd(veth, addr); err != nil {
return err
}

if err := netlink.LinkSetUp(veth); err != nil {
return err
}
return nil
}

func unshareCmd(ns netns.NsHandle, args string) error {
Expand Down

0 comments on commit 648cb51

Please sign in to comment.