Fix #I4KI81 reason: modify kata-containers version and update it to 1.11.1 Signed-off-by: holyfei <yangfeiyu20092010@163.com>
376 lines
13 KiB
Diff
376 lines
13 KiB
Diff
From dbbf8c5deb14d8033b2e863fb0eb731523af2a47 Mon Sep 17 00:00:00 2001
|
|
From: jiangpengfei <jiangpengfei9@huawei.com>
|
|
Date: Wed, 19 Aug 2020 09:58:07 +0800
|
|
Subject: [PATCH 44/50] network: support dpdk vhost_user net device
|
|
|
|
reason: support dpdk vhost_user net device
|
|
|
|
Signed-off-by: jiangpengfei <jiangpengfei9@huawei.com>
|
|
---
|
|
vendor/github.com/intel/govmm/qemu/qmp.go | 3 +-
|
|
virtcontainers/hypervisor.go | 3 ++
|
|
virtcontainers/network.go | 49 ++++++++++++++------
|
|
virtcontainers/pkg/types/types.go | 2 +
|
|
virtcontainers/qemu.go | 75 +++++++++++++++++++++++++++++++
|
|
virtcontainers/sandbox.go | 7 ++-
|
|
virtcontainers/vhostuser_endpoint.go | 18 ++++++--
|
|
virtcontainers/vhostuser_endpoint_test.go | 7 ++-
|
|
8 files changed, 143 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/vendor/github.com/intel/govmm/qemu/qmp.go b/vendor/github.com/intel/govmm/qemu/qmp.go
|
|
index a64039de..0cb82ffa 100644
|
|
--- a/vendor/github.com/intel/govmm/qemu/qmp.go
|
|
+++ b/vendor/github.com/intel/govmm/qemu/qmp.go
|
|
@@ -970,11 +970,12 @@ func (q *QMP) ExecuteNetdevAdd(ctx context.Context, netdevType, netdevID, ifname
|
|
// ExecuteNetdevChardevAdd adds a Net device to a QEMU instance
|
|
// using the netdev_add command. netdevID is the id of the device to add.
|
|
// Must be valid QMP identifier.
|
|
-func (q *QMP) ExecuteNetdevChardevAdd(ctx context.Context, netdevType, netdevID, chardev string, queues int) error {
|
|
+func (q *QMP) ExecuteNetdevChardevAdd(ctx context.Context, netdevType, netdevID, chardev string, vhostforce bool, queues int) error {
|
|
args := map[string]interface{}{
|
|
"type": netdevType,
|
|
"id": netdevID,
|
|
"chardev": chardev,
|
|
+ "vhostforce": vhostforce,
|
|
}
|
|
if queues > 1 {
|
|
args["queues"] = queues
|
|
diff --git a/virtcontainers/hypervisor.go b/virtcontainers/hypervisor.go
|
|
index c0723daa..60f1d190 100644
|
|
--- a/virtcontainers/hypervisor.go
|
|
+++ b/virtcontainers/hypervisor.go
|
|
@@ -132,6 +132,9 @@ const (
|
|
// vhostuserDev is a Vhost-user device type
|
|
vhostuserDev
|
|
|
|
+ // vhostUserNetDev is a Vhost-user net device type
|
|
+ vhostUserNetDev
|
|
+
|
|
// CPUDevice is CPU device type
|
|
cpuDev
|
|
|
|
diff --git a/virtcontainers/network.go b/virtcontainers/network.go
|
|
index 488bd00c..a0c64356 100644
|
|
--- a/virtcontainers/network.go
|
|
+++ b/virtcontainers/network.go
|
|
@@ -13,6 +13,7 @@ import (
|
|
"math/rand"
|
|
"net"
|
|
"os"
|
|
+ "path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"sort"
|
|
@@ -65,7 +66,8 @@ const (
|
|
)
|
|
|
|
var (
|
|
- regInfName = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_\-.]*$`)
|
|
+ regInfName = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_\-.]*$`)
|
|
+ regVhostName = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9\-.]{0,127}$`)
|
|
)
|
|
|
|
//IsValid checks if a model is valid
|
|
@@ -132,11 +134,12 @@ type NetlinkIface struct {
|
|
// NetworkInfo gathers all information related to a network interface.
|
|
// It can be used to store the description of the underlying network.
|
|
type NetworkInfo struct {
|
|
- Device string
|
|
- Iface NetlinkIface
|
|
- Addrs []netlink.Addr
|
|
- Routes []netlink.Route
|
|
- DNS DNSInfo
|
|
+ Device string
|
|
+ Iface NetlinkIface
|
|
+ Addrs []netlink.Addr
|
|
+ Routes []netlink.Route
|
|
+ DNS DNSInfo
|
|
+ VhostUserSocket string
|
|
}
|
|
|
|
// NetworkInterface defines a network interface.
|
|
@@ -1198,15 +1201,11 @@ func createEndpoint(netInfo NetworkInfo, idx int, model NetInterworkingModel, li
|
|
return endpoint, err
|
|
}
|
|
|
|
- // Check if this is a dummy interface which has a vhost-user socket associated with it
|
|
- socketPath, err := vhostUserSocketPath(netInfo)
|
|
- if err != nil {
|
|
- return nil, err
|
|
- }
|
|
-
|
|
- if socketPath != "" {
|
|
+ // Currently, we only accept the vhost-user socket paas from user input
|
|
+ // interface info json file
|
|
+ if netInfo.VhostUserSocket != "" {
|
|
networkLogger().WithField("interface", netInfo.Iface.Name).Info("VhostUser network interface found")
|
|
- endpoint, err = createVhostUserEndpoint(netInfo, socketPath)
|
|
+ endpoint, err = createVhostUserEndpoint(netInfo, netInfo.VhostUserSocket)
|
|
return endpoint, err
|
|
}
|
|
|
|
@@ -1481,6 +1480,24 @@ func verifyIP(ip string) (*net.IP, error) {
|
|
return &netIP, nil
|
|
}
|
|
|
|
+// verifyVhostSocket verifies the vhost socket is valid or not
|
|
+func verifyVhostSocket(vhostSocket string) error {
|
|
+ if vhostSocket == "" {
|
|
+ networkLogger().Debug("no dpdk network")
|
|
+ return nil
|
|
+ }
|
|
+ if regVhostName.FindAllString(filepath.Base(vhostSocket), -1) == nil {
|
|
+ return fmt.Errorf("invalid input of vhostSocket name, please check the rules")
|
|
+ }
|
|
+ info, err := os.Stat(vhostSocket)
|
|
+ if err != nil || info.IsDir() || info.Mode()&os.ModeSocket == 0 {
|
|
+ return fmt.Errorf("invalid vhost socket: %v", vhostSocket)
|
|
+ }
|
|
+
|
|
+ networkLogger().WithField("vhostSocket", vhostSocket).Infof("using dpdk network, socket file is: %s ", vhostSocket)
|
|
+ return nil
|
|
+}
|
|
+
|
|
// validInterface check the input interface valid or not
|
|
func validInterface(inf *vcTypes.Interface, enableCompatOldCNI bool) error {
|
|
if enableCompatOldCNI && verifyInterfaceName(inf.Device) != nil {
|
|
@@ -1503,6 +1520,10 @@ func validInterface(inf *vcTypes.Interface, enableCompatOldCNI bool) error {
|
|
return err
|
|
}
|
|
|
|
+ if err := verifyVhostSocket(inf.VhostUserSocket); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
// Currently, only one IP address can be passed, which reduces the test entry and fault injection.
|
|
if len(inf.IPAddresses) > 0 {
|
|
if len(inf.IPAddresses) != 1 {
|
|
diff --git a/virtcontainers/pkg/types/types.go b/virtcontainers/pkg/types/types.go
|
|
index b41b0c75..dccd92f8 100644
|
|
--- a/virtcontainers/pkg/types/types.go
|
|
+++ b/virtcontainers/pkg/types/types.go
|
|
@@ -29,6 +29,8 @@ type Interface struct {
|
|
// library, regarding each type of link. Here is a non exhaustive
|
|
// list: "veth", "macvtap", "vlan", "macvlan", "tap", ...
|
|
LinkType string `json:"linkType,omitempty"`
|
|
+ // VhostUserSocket is DPDK-backed vHost user ports.
|
|
+ VhostUserSocket string `json:"vhostUserSocket,omitempty"`
|
|
}
|
|
|
|
// Route describes a network route.
|
|
diff --git a/virtcontainers/qemu.go b/virtcontainers/qemu.go
|
|
index 657b6be7..84797e0d 100644
|
|
--- a/virtcontainers/qemu.go
|
|
+++ b/virtcontainers/qemu.go
|
|
@@ -1279,6 +1279,78 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
|
|
return err
|
|
}
|
|
|
|
+func (q *qemu) hotplugVhostUserNetDevice(endpoint Endpoint, op operation) error {
|
|
+ err := q.qmpSetup()
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ device := endpoint.(*VhostUserEndpoint)
|
|
+
|
|
+ charDevID := utils.MakeNameID("char", device.ID, maxDevIDSize)
|
|
+ devID := utils.MakeNameID("virtio", device.ID, maxDevIDSize)
|
|
+
|
|
+ if op == addDevice {
|
|
+ // Add chardev specifying the appropriate socket.
|
|
+ if err = q.qmpMonitorCh.qmp.ExecuteCharDevUnixSocketAdd(q.qmpMonitorCh.ctx, charDevID, device.SocketPath, true, false); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ defer func() {
|
|
+ if err != nil {
|
|
+ errRb := q.qmpMonitorCh.qmp.ExecuteChardevDel(q.qmpMonitorCh.ctx, charDevID)
|
|
+ if errRb != nil {
|
|
+ q.Logger().Errorf("deletes a net device roll back failed. charDev id:%s", charDevID)
|
|
+ }
|
|
+ }
|
|
+ }()
|
|
+
|
|
+ netDevType := "vhost-user"
|
|
+ // Add netdev of type vhost-user.
|
|
+ if err = q.qmpMonitorCh.qmp.ExecuteNetdevChardevAdd(q.qmpMonitorCh.ctx, netDevType, devID, charDevID, true, 0); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ defer func() {
|
|
+ if err != nil {
|
|
+ errRb := q.qmpMonitorCh.qmp.ExecuteNetdevDel(q.qmpMonitorCh.ctx, devID)
|
|
+ if errRb != nil {
|
|
+ q.Logger().Errorf("deletes a net device roll back failed. netDev id:%s", devID)
|
|
+ }
|
|
+ }
|
|
+ }()
|
|
+
|
|
+ var addr, bus, pciAddr string
|
|
+ addr, bus, pciAddr, err = q.getPciAddress(device.ID, types.PCI)
|
|
+ if err != nil {
|
|
+ return nil
|
|
+ }
|
|
+ defer func() {
|
|
+ if err != nil {
|
|
+ q.putPciAddress(device.ID)
|
|
+ }
|
|
+ }()
|
|
+
|
|
+ endpoint.SetPciAddr(pciAddr)
|
|
+
|
|
+ // Add virtio-net-pci device.
|
|
+ err = q.qmpMonitorCh.qmp.ExecuteNetPCIDeviceAdd(q.qmpMonitorCh.ctx, devID, devID, device.HardAddr, addr, bus, romFile, 0, q.arch.runNested())
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ if err = q.putPciAddress(device.ID); err != nil {
|
|
+ return err
|
|
+ }
|
|
+ if err = q.qmpMonitorCh.qmp.ExecuteDeviceDel(q.qmpMonitorCh.ctx, devID); err != nil {
|
|
+ return err
|
|
+ }
|
|
+ if err = q.qmpMonitorCh.qmp.ExecuteNetdevDel(q.qmpMonitorCh.ctx, devID); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ return nil
|
|
+}
|
|
+
|
|
func (q *qemu) hotplugVhostUserDevice(vAttr *config.VhostUserDeviceAttrs, op operation) error {
|
|
err := q.qmpSetup()
|
|
if err != nil {
|
|
@@ -1510,6 +1582,9 @@ func (q *qemu) hotplugDevice(devInfo interface{}, devType deviceType, op operati
|
|
case vhostuserDev:
|
|
vAttr := devInfo.(*config.VhostUserDeviceAttrs)
|
|
return nil, q.hotplugVhostUserDevice(vAttr, op)
|
|
+ case vhostUserNetDev:
|
|
+ device := devInfo.(Endpoint)
|
|
+ return nil, q.hotplugVhostUserNetDevice(device, op)
|
|
default:
|
|
return nil, fmt.Errorf("cannot hotplug device: unsupported device type '%v'", devType)
|
|
}
|
|
diff --git a/virtcontainers/sandbox.go b/virtcontainers/sandbox.go
|
|
index 0d599267..e6f155a3 100644
|
|
--- a/virtcontainers/sandbox.go
|
|
+++ b/virtcontainers/sandbox.go
|
|
@@ -946,7 +946,8 @@ func (s *Sandbox) generateNetInfo(inf *vcTypes.Interface) (NetworkInfo, error) {
|
|
},
|
|
Type: inf.LinkType,
|
|
},
|
|
- Addrs: addrs,
|
|
+ Addrs: addrs,
|
|
+ VhostUserSocket: inf.VhostUserSocket,
|
|
}, nil
|
|
}
|
|
|
|
@@ -961,6 +962,10 @@ func (s *Sandbox) AddInterface(inf *vcTypes.Interface) (grpcIf *vcTypes.Interfac
|
|
if ep.Name() == inf.Name {
|
|
return nil, fmt.Errorf("interface %s is already exist", inf.Name)
|
|
}
|
|
+
|
|
+ if ep.Properties().VhostUserSocket != "" && inf.VhostUserSocket != "" {
|
|
+ return nil, fmt.Errorf("sandbox %s only support one dpdk socket", s.ID())
|
|
+ }
|
|
}
|
|
|
|
netInfo, err := s.generateNetInfo(inf)
|
|
diff --git a/virtcontainers/vhostuser_endpoint.go b/virtcontainers/vhostuser_endpoint.go
|
|
index bb4a67be..2fc3d837 100644
|
|
--- a/virtcontainers/vhostuser_endpoint.go
|
|
+++ b/virtcontainers/vhostuser_endpoint.go
|
|
@@ -12,6 +12,7 @@ import (
|
|
|
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
|
+ "github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
|
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
|
)
|
|
|
|
@@ -23,6 +24,7 @@ const hostSocketSearchPath = "/tmp/vhostuser_%s/vhu.sock"
|
|
|
|
// VhostUserEndpoint represents a vhost-user socket based network interface
|
|
type VhostUserEndpoint struct {
|
|
+ ID string
|
|
// Path to the vhost-user socket on the host system
|
|
SocketPath string
|
|
// MAC address of the interface
|
|
@@ -99,18 +101,28 @@ func (endpoint *VhostUserEndpoint) Detach(netNsCreated bool, netNsPath string) e
|
|
|
|
// HotAttach for vhostuser endpoint not supported yet
|
|
func (endpoint *VhostUserEndpoint) HotAttach(h hypervisor) error {
|
|
- return fmt.Errorf("VhostUserEndpoint does not support Hot attach")
|
|
+ networkLogger().Debug("Hot attaching vhost-user endpoint")
|
|
+ if _, err := h.hotplugAddDevice(endpoint, vhostUserNetDev); err != nil {
|
|
+ return err
|
|
+ }
|
|
+ return nil
|
|
}
|
|
|
|
// HotDetach for vhostuser endpoint not supported yet
|
|
func (endpoint *VhostUserEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
|
- return fmt.Errorf("VhostUserEndpoint does not support Hot detach")
|
|
+ networkLogger().Debug("Hot detaching vhost-user endpoint")
|
|
+ if _, err := h.hotplugRemoveDevice(endpoint, vhostUserNetDev); err != nil {
|
|
+ networkLogger().WithError(err).Errorf("Error detach vhostUserSocket")
|
|
+ return err
|
|
+ }
|
|
+ return nil
|
|
}
|
|
|
|
// Create a vhostuser endpoint
|
|
func createVhostUserEndpoint(netInfo NetworkInfo, socket string) (*VhostUserEndpoint, error) {
|
|
-
|
|
+ uniqueID := uuid.Generate().String()
|
|
vhostUserEndpoint := &VhostUserEndpoint{
|
|
+ ID: uniqueID,
|
|
SocketPath: socket,
|
|
HardAddr: netInfo.Iface.HardwareAddr.String(),
|
|
IfaceName: netInfo.Iface.Name,
|
|
diff --git a/virtcontainers/vhostuser_endpoint_test.go b/virtcontainers/vhostuser_endpoint_test.go
|
|
index ad013e12..584490cc 100644
|
|
--- a/virtcontainers/vhostuser_endpoint_test.go
|
|
+++ b/virtcontainers/vhostuser_endpoint_test.go
|
|
@@ -11,6 +11,7 @@ import (
|
|
"os"
|
|
"testing"
|
|
|
|
+ "github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
@@ -95,7 +96,7 @@ func TestVhostUserEndpoint_HotAttach(t *testing.T) {
|
|
h := &mockHypervisor{}
|
|
|
|
err := v.HotAttach(h)
|
|
- assert.Error(err)
|
|
+ assert.NoError(err)
|
|
}
|
|
|
|
func TestVhostUserEndpoint_HotDetach(t *testing.T) {
|
|
@@ -109,10 +110,11 @@ func TestVhostUserEndpoint_HotDetach(t *testing.T) {
|
|
h := &mockHypervisor{}
|
|
|
|
err := v.HotDetach(h, true, "")
|
|
- assert.Error(err)
|
|
+ assert.NoError(err)
|
|
}
|
|
|
|
func TestCreateVhostUserEndpoint(t *testing.T) {
|
|
+ uniqueID := uuid.Generate().String()
|
|
macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x48}
|
|
ifcName := "vhost-deadbeef"
|
|
socket := "/tmp/vhu_192.168.0.1"
|
|
@@ -128,6 +130,7 @@ func TestCreateVhostUserEndpoint(t *testing.T) {
|
|
}
|
|
|
|
expected := &VhostUserEndpoint{
|
|
+ ID: uniqueID,
|
|
SocketPath: socket,
|
|
HardAddr: macAddr.String(),
|
|
IfaceName: ifcName,
|
|
--
|
|
2.14.3 (Apple Git-98)
|
|
|