Skip to content

Commit

Permalink
virt-chroot will gain the ability to create and remove mediated devices
Browse files Browse the repository at this point in the history
Signed-off-by: Vladik Romanovsky <[email protected]>
  • Loading branch information
vladikr committed Aug 11, 2021
1 parent 1873e35 commit 7439117
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/virt-chroot/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"main.go",
"mdev-handler.go",
"selinux.go",
"tap-device-maker.go",
],
Expand All @@ -14,6 +15,7 @@ go_library(
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/vishvananda/netlink:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
)

Expand Down
10 changes: 10 additions & 0 deletions cmd/virt-chroot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,22 @@ func main() {
createTapCmd.Flags().Uint32("queue-number", 0, "the number of queues to use on multi-queued devices")
createTapCmd.Flags().Uint32("mtu", 1500, "the link MTU of the tap device")

createMDEVCmd := NewCreateMDEVCommand()
createMDEVCmd.Flags().String("type", "", "the type of a mediated device")
createMDEVCmd.Flags().String("parent", "", "id of a parent (e.g. PCI_ID) for the new mediated device")
createMDEVCmd.Flags().String("uuid", "", "uuid for the new mediated device")

removeMDEVCmd := NewRemoveMDEVCommand()
removeMDEVCmd.Flags().String("uuid", "", "uuid of the mediated device to remove")

rootCmd.AddCommand(
execCmd,
mntCmd,
umntCmd,
selinuxCmd,
createTapCmd,
createMDEVCmd,
removeMDEVCmd,
)

if err := rootCmd.Execute(); err != nil {
Expand Down
109 changes: 109 additions & 0 deletions cmd/virt-chroot/mdev-handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/spf13/cobra"
utilwait "k8s.io/apimachinery/pkg/util/wait"
)

var mdevBasePath string = "/sys/bus/mdev/devices"
var mdevClassBusPath string = "/sys/class/mdev_bus"

func createMDEVType(mdevType string, parentID string, uid string) error {

path := filepath.Join(mdevClassBusPath, parentID, "mdev_supported_types", mdevType, "create")
// wait for interface to become available
if !isInterfaceAvailable(path) {
msg := fmt.Sprintf("failed to create mdev type %s, interface is not available %s", mdevType, path)
errMsg := fmt.Errorf(msg)
fmt.Println(msg)
return errMsg
}
f, err := os.OpenFile(path, os.O_WRONLY, 0200)
if err != nil {
fmt.Printf("failed to create mdev type %s, can't open path %s\n", mdevType, path)
return err
}

defer f.Close()

if _, err = f.WriteString(uid); err != nil {
fmt.Printf("failed to create mdev type %s, can't write to %s\n", mdevType, path)
return err
}
fmt.Printf("Successfully created mdev %s - %s\n", mdevType, uid)
return nil
}

func removeMDEVType(mdevUUID string) error {
removePath := filepath.Join(mdevBasePath, mdevUUID, "remove")
// wait for interface to become available
if !isInterfaceAvailable(removePath) {
msg := fmt.Sprintf("failed to remove mdev %s, interface is not available %s", mdevUUID, removePath)
errMsg := fmt.Errorf(msg)
fmt.Println(msg)
return errMsg
}

f, err := os.OpenFile(removePath, os.O_WRONLY, 0200)
if err != nil {
fmt.Printf("failed to remove mdev %s, can't open path %s\n", mdevUUID, removePath)
return err
}

defer f.Close()

if _, err = f.WriteString("1"); err != nil {
fmt.Printf("failed to remove mdev %s, can't write to %s\n", mdevUUID, removePath)
return err
}
fmt.Printf("Successfully removed mdev %s\n", mdevUUID)
return nil
}

func NewCreateMDEVCommand() *cobra.Command {
return &cobra.Command{
Use: "create-mdev",
Short: "create a mediate device in a given PID net ns",
RunE: func(cmd *cobra.Command, args []string) error {
mdevType := cmd.Flag("type").Value.String()
parentID := cmd.Flag("parent").Value.String()
UID := cmd.Flag("uuid").Value.String()
return createMDEVType(mdevType, parentID, UID)
},
}
}

func NewRemoveMDEVCommand() *cobra.Command {
return &cobra.Command{
Use: "remove-mdev",
Short: "remove a mediate device",
RunE: func(cmd *cobra.Command, args []string) error {
mdevUUID := cmd.Flag("uuid").Value.String()
return removeMDEVType(mdevUUID)
},
}
}

func isInterfaceAvailable(interfacePath string) bool {
connectionInterval := 1 * time.Second
connectionTimeout := 5 * time.Second

err := utilwait.PollImmediate(connectionInterval, connectionTimeout, func() (done bool, err error) {
_, err = os.Stat(interfacePath)
if err != nil {
return false, nil
}
return true, nil
})

if err != nil {
fmt.Printf("interface %s is not available after multiple tries\n", interfacePath)
return false
}
return true
}
12 changes: 12 additions & 0 deletions pkg/virt-handler/virt-chroot/virt-chroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ func UmountChroot(path string) *exec.Cmd {
return exec.Command(binaryPath, args...)
}

func CreateMDEVType(mdevType string, parentID string, uuid string) *exec.Cmd {
args := append(getBaseArgs(), "create-mdev")
args = append(args, "--type", mdevType, "--parent", parentID, "--uuid", uuid)
return exec.Command(binaryPath, args...)
}

func RemoveMDEVType(mdevUUID string) *exec.Cmd {
args := append(getBaseArgs(), "remove-mdev")
args = append(args, "--uuid", mdevUUID)
return exec.Command(binaryPath, args...)
}

// For general purposes
func ExecChroot(args ...string) *exec.Cmd {
return exec.Command(binaryPath, args...)
Expand Down

0 comments on commit 7439117

Please sign in to comment.