network: Refactor network.go

Split endpoint implementations into their own file.

Fixes #799

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
This commit is contained in:
Archana Shinde 2018-10-08 22:25:42 -07:00
parent 7fb2706667
commit adcd9106f9
7 changed files with 791 additions and 725 deletions

View File

@ -0,0 +1,116 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"github.com/containernetworking/plugins/pkg/ns"
)
// BridgedMacvlanEndpoint represents a macvlan endpoint that is bridged to the VM
type BridgedMacvlanEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
}
func createBridgedMacvlanNetworkEndpoint(idx int, ifName string, interworkingModel NetInterworkingModel) (*BridgedMacvlanEndpoint, error) {
if idx < 0 {
return &BridgedMacvlanEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
}
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
if err != nil {
return nil, err
}
endpoint := &BridgedMacvlanEndpoint{
NetPair: netPair,
EndpointType: BridgedMacvlanEndpointType,
}
if ifName != "" {
endpoint.NetPair.VirtIface.Name = ifName
}
return endpoint, nil
}
// Properties returns properties of the interface.
func (endpoint *BridgedMacvlanEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the veth interface in the network pair.
func (endpoint *BridgedMacvlanEndpoint) Name() string {
return endpoint.NetPair.VirtIface.Name
}
// HardwareAddr returns the mac address that is assigned to the tap interface
// in th network pair.
func (endpoint *BridgedMacvlanEndpoint) HardwareAddr() string {
return endpoint.NetPair.TAPIface.HardAddr
}
// Type identifies the endpoint as a virtual endpoint.
func (endpoint *BridgedMacvlanEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties for the endpoint.
func (endpoint *BridgedMacvlanEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) NetworkPair() *NetworkInterfacePair {
return &endpoint.NetPair
}
// Attach for virtual endpoint bridges the network pair and adds the
// tap interface of the network pair to the hypervisor.
func (endpoint *BridgedMacvlanEndpoint) Attach(h hypervisor) error {
networkLogger().Info("Attaching macvlan endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual ep")
return err
}
return h.addDevice(endpoint, netDev)
}
// Detach for the virtual endpoint tears down the tap and bridge
// created for the veth interface.
func (endpoint *BridgedMacvlanEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// The network namespace would have been deleted at this point
// if it has not been created by virtcontainers.
if !netNsCreated {
return nil
}
networkLogger().Info("Detaching virtual endpoint")
return doNetNS(netNsPath, func(_ ns.NetNS) error {
//return xconnectVMNetwork(&(endpoint.NetPair), false, 0, false, endpoint.EndpointType)
return xconnectVMNetwork(endpoint, false, 0, false)
})
}
// HotAttach for physical endpoint not supported yet
func (endpoint *BridgedMacvlanEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot attach")
}
// HotDetach for physical endpoint not supported yet
func (endpoint *BridgedMacvlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot detach")
}

View File

@ -0,0 +1,87 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
)
// Endpoint represents a physical or virtual network interface.
type Endpoint interface {
Properties() NetworkInfo
Name() string
HardwareAddr() string
Type() EndpointType
PciAddr() string
NetworkPair() *NetworkInterfacePair
SetProperties(NetworkInfo)
Attach(hypervisor) error
Detach(netNsCreated bool, netNsPath string) error
HotAttach(h hypervisor) error
HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error
}
// EndpointType identifies the type of the network endpoint.
type EndpointType string
const (
// PhysicalEndpointType is the physical network interface.
PhysicalEndpointType EndpointType = "physical"
// VirtualEndpointType is the virtual network interface.
VirtualEndpointType EndpointType = "virtual"
// VhostUserEndpointType is the vhostuser network interface.
VhostUserEndpointType EndpointType = "vhost-user"
// BridgedMacvlanEndpointType is macvlan network interface.
BridgedMacvlanEndpointType EndpointType = "macvlan"
// MacvtapEndpointType is macvtap network interface.
MacvtapEndpointType EndpointType = "macvtap"
)
// Set sets an endpoint type based on the input string.
func (endpointType *EndpointType) Set(value string) error {
switch value {
case "physical":
*endpointType = PhysicalEndpointType
return nil
case "virtual":
*endpointType = VirtualEndpointType
return nil
case "vhost-user":
*endpointType = VhostUserEndpointType
return nil
case "macvlan":
*endpointType = BridgedMacvlanEndpointType
return nil
case "macvtap":
*endpointType = MacvtapEndpointType
return nil
default:
return fmt.Errorf("Unknown endpoint type %s", value)
}
}
// String converts an endpoint type to a string.
func (endpointType *EndpointType) String() string {
switch *endpointType {
case PhysicalEndpointType:
return string(PhysicalEndpointType)
case VirtualEndpointType:
return string(VirtualEndpointType)
case VhostUserEndpointType:
return string(VhostUserEndpointType)
case BridgedMacvlanEndpointType:
return string(BridgedMacvlanEndpointType)
case MacvtapEndpointType:
return string(MacvtapEndpointType)
default:
return ""
}
}

View File

@ -0,0 +1,101 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"os"
)
// MacvtapEndpoint represents a macvtap endpoint
type MacvtapEndpoint struct {
EndpointProperties NetworkInfo
EndpointType EndpointType
VMFds []*os.File
VhostFds []*os.File
PCIAddr string
}
func createMacvtapNetworkEndpoint(netInfo NetworkInfo) (*MacvtapEndpoint, error) {
endpoint := &MacvtapEndpoint{
EndpointType: MacvtapEndpointType,
EndpointProperties: netInfo,
}
return endpoint, nil
}
// Properties returns the properties of the macvtap interface.
func (endpoint *MacvtapEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// HardwareAddr returns the mac address of the macvtap network interface.
func (endpoint *MacvtapEndpoint) HardwareAddr() string {
return endpoint.EndpointProperties.Iface.HardwareAddr.String()
}
// Name returns name of the macvtap interface.
func (endpoint *MacvtapEndpoint) Name() string {
return endpoint.EndpointProperties.Iface.Name
}
// Type indentifies the endpoint as a macvtap endpoint.
func (endpoint *MacvtapEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties of the macvtap endpoint.
func (endpoint *MacvtapEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// Attach for macvtap endpoint passes macvtap device to the hypervisor.
func (endpoint *MacvtapEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "macvtap").Info("Attaching endpoint")
var err error
endpoint.VMFds, err = createMacvtapFds(endpoint.EndpointProperties.Iface.Index, int(h.hypervisorConfig().NumVCPUs))
if err != nil {
return fmt.Errorf("Could not setup macvtap fds %s: %s", endpoint.EndpointProperties.Iface.Name, err)
}
if !h.hypervisorConfig().DisableVhostNet {
vhostFds, err := createVhostFds(int(h.hypervisorConfig().NumVCPUs))
if err != nil {
return fmt.Errorf("Could not setup vhost fds %s : %s", endpoint.EndpointProperties.Iface.Name, err)
}
endpoint.VhostFds = vhostFds
}
return h.addDevice(endpoint, netDev)
}
// Detach for macvtap endpoint does nothing.
func (endpoint *MacvtapEndpoint) Detach(netNsCreated bool, netNsPath string) error {
networkLogger().WithField("endpoint-type", "macvtap").Info("Detaching endpoint")
return nil
}
// HotAttach for macvtap endpoint not supported yet
func (endpoint *MacvtapEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("MacvtapEndpoint does not support Hot attach")
}
// HotDetach for macvtap endpoint not supported yet
func (endpoint *MacvtapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("MacvtapEndpoint does not support Hot detach")
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *MacvtapEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *MacvtapEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}

View File

@ -7,29 +7,22 @@ package virtcontainers
import (
cryptoRand "crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/safchain/ethtool"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
"github.com/kata-containers/agent/protocols/grpc"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
"github.com/kata-containers/runtime/virtcontainers/utils"
)
@ -148,548 +141,10 @@ type NetworkConfig struct {
InterworkingModel NetInterworkingModel
}
// Endpoint represents a physical or virtual network interface.
type Endpoint interface {
Properties() NetworkInfo
Name() string
HardwareAddr() string
Type() EndpointType
PciAddr() string
NetworkPair() *NetworkInterfacePair
SetProperties(NetworkInfo)
Attach(hypervisor) error
Detach(netNsCreated bool, netNsPath string) error
HotAttach(h hypervisor) error
HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error
}
// VirtualEndpoint gathers a network pair and its properties.
type VirtualEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
Physical bool
EndpointType EndpointType
PCIAddr string
}
// PhysicalEndpoint gathers a physical network interface and its properties
type PhysicalEndpoint struct {
IfaceName string
HardAddr string
EndpointProperties NetworkInfo
EndpointType EndpointType
BDF string
Driver string
VendorDeviceID string
PCIAddr string
}
// VhostUserEndpoint represents a vhost-user socket based network interface
type VhostUserEndpoint struct {
// Path to the vhost-user socket on the host system
SocketPath string
// MAC address of the interface
HardAddr string
IfaceName string
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
}
// BridgedMacvlanEndpoint represents a macvlan endpoint that is bridged to the VM
type BridgedMacvlanEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
}
// MacvtapEndpoint represents a macvtap endpoint
type MacvtapEndpoint struct {
EndpointProperties NetworkInfo
EndpointType EndpointType
VMFds []*os.File
VhostFds []*os.File
PCIAddr string
}
// Properties returns properties for the veth interface in the network pair.
func (endpoint *VirtualEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the veth interface in the network pair.
func (endpoint *VirtualEndpoint) Name() string {
return endpoint.NetPair.VirtIface.Name
}
// HardwareAddr returns the mac address that is assigned to the tap interface
// in th network pair.
func (endpoint *VirtualEndpoint) HardwareAddr() string {
return endpoint.NetPair.TAPIface.HardAddr
}
// Type identifies the endpoint as a virtual endpoint.
func (endpoint *VirtualEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VirtualEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *VirtualEndpoint) NetworkPair() *NetworkInterfacePair {
return &endpoint.NetPair
}
// SetProperties sets the properties for the endpoint.
func (endpoint *VirtualEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
func networkLogger() *logrus.Entry {
return virtLog.WithField("subsystem", "network")
}
// Attach for virtual endpoint bridges the network pair and adds the
// tap interface of the network pair to the hypervisor.
func (endpoint *VirtualEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "virtual").Info("Attaching endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual endpoint")
return err
}
return h.addDevice(endpoint, netDev)
}
// Detach for the virtual endpoint tears down the tap and bridge
// created for the veth interface.
func (endpoint *VirtualEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// The network namespace would have been deleted at this point
// if it has not been created by virtcontainers.
if !netNsCreated {
return nil
}
networkLogger().WithField("endpoint-type", "virtual").Info("Detaching endpoint")
return doNetNS(netNsPath, func(_ ns.NetNS) error {
return xconnectVMNetwork(endpoint, false, 0, false)
})
}
// HotAttach for the virtual endpoint uses hot plug device
func (endpoint *VirtualEndpoint) HotAttach(h hypervisor) error {
networkLogger().Info("Hot attaching virtual endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual ep")
return err
}
if _, err := h.hotplugAddDevice(endpoint, netDev); err != nil {
networkLogger().WithError(err).Error("Error attach virtual ep")
return err
}
return nil
}
// HotDetach for the virtual endpoint uses hot pull device
func (endpoint *VirtualEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
if !netNsCreated {
return nil
}
networkLogger().Info("Hot detaching virtual endpoint")
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
return xconnectVMNetwork(endpoint, false, 0, h.hypervisorConfig().DisableVhostNet)
}); err != nil {
networkLogger().WithError(err).Warn("Error un-bridging virtual ep")
}
if _, err := h.hotplugRemoveDevice(endpoint, netDev); err != nil {
networkLogger().WithError(err).Error("Error detach virtual ep")
return err
}
return nil
}
// Properties returns the properties of the interface.
func (endpoint *VhostUserEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the interface.
func (endpoint *VhostUserEndpoint) Name() string {
return endpoint.IfaceName
}
// HardwareAddr returns the mac address of the vhostuser network interface
func (endpoint *VhostUserEndpoint) HardwareAddr() string {
return endpoint.HardAddr
}
// Type indentifies the endpoint as a vhostuser endpoint.
func (endpoint *VhostUserEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties of the endpoint.
func (endpoint *VhostUserEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VhostUserEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *VhostUserEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}
// Attach for vhostuser endpoint
func (endpoint *VhostUserEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "vhostuser").Info("Attaching endpoint")
// Generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
d := config.VhostUserDeviceAttrs{
DevID: id,
SocketPath: endpoint.SocketPath,
MacAddress: endpoint.HardAddr,
Type: config.VhostUserNet,
}
return h.addDevice(d, vhostuserDev)
}
// Detach for vhostuser endpoint
func (endpoint *VhostUserEndpoint) Detach(netNsCreated bool, netNsPath string) error {
networkLogger().WithField("endpoint-type", "vhostuser").Info("Detaching endpoint")
return nil
}
// HotAttach for vhostuser endpoint not supported yet
func (endpoint *VhostUserEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("VhostUserEndpoint does not support Hot attach")
}
// 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")
}
// Create a vhostuser endpoint
func createVhostUserEndpoint(netInfo NetworkInfo, socket string) (*VhostUserEndpoint, error) {
vhostUserEndpoint := &VhostUserEndpoint{
SocketPath: socket,
HardAddr: netInfo.Iface.HardwareAddr.String(),
IfaceName: netInfo.Iface.Name,
EndpointType: VhostUserEndpointType,
}
return vhostUserEndpoint, nil
}
// Properties returns the properties of the physical interface.
func (endpoint *PhysicalEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// HardwareAddr returns the mac address of the physical network interface.
func (endpoint *PhysicalEndpoint) HardwareAddr() string {
return endpoint.HardAddr
}
// Name returns name of the physical interface.
func (endpoint *PhysicalEndpoint) Name() string {
return endpoint.IfaceName
}
// Type indentifies the endpoint as a physical endpoint.
func (endpoint *PhysicalEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *PhysicalEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// SetProperties sets the properties of the physical endpoint.
func (endpoint *PhysicalEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *PhysicalEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}
// Attach for physical endpoint binds the physical network interface to
// vfio-pci and adds device to the hypervisor with vfio-passthrough.
func (endpoint *PhysicalEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "physical").Info("Attaching endpoint")
// Unbind physical interface from host driver and bind to vfio
// so that it can be passed to qemu.
if err := bindNICToVFIO(endpoint); err != nil {
return err
}
// TODO: use device manager as general device management entrance
d := config.VFIODev{
BDF: endpoint.BDF,
}
return h.addDevice(d, vfioDev)
}
// Detach for physical endpoint unbinds the physical network interface from vfio-pci
// and binds it back to the saved host driver.
func (endpoint *PhysicalEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// Bind back the physical network interface to host.
// We need to do this even if a new network namespace has not
// been created by virtcontainers.
networkLogger().WithField("endpoint-type", "physical").Info("Detaching endpoint")
// We do not need to enter the network namespace to bind back the
// physical interface to host driver.
return bindNICToHost(endpoint)
}
// HotAttach for physical endpoint not supported yet
func (endpoint *PhysicalEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("PhysicalEndpoint does not support Hot attach")
}
// HotDetach for physical endpoint not supported yet
func (endpoint *PhysicalEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("PhysicalEndpoint does not support Hot detach")
}
// Macvlan
// Properties returns properties of the interface.
func (endpoint *BridgedMacvlanEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the veth interface in the network pair.
func (endpoint *BridgedMacvlanEndpoint) Name() string {
return endpoint.NetPair.VirtIface.Name
}
// HardwareAddr returns the mac address that is assigned to the tap interface
// in th network pair.
func (endpoint *BridgedMacvlanEndpoint) HardwareAddr() string {
return endpoint.NetPair.TAPIface.HardAddr
}
// Type identifies the endpoint as a virtual endpoint.
func (endpoint *BridgedMacvlanEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties for the endpoint.
func (endpoint *BridgedMacvlanEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *BridgedMacvlanEndpoint) NetworkPair() *NetworkInterfacePair {
return &endpoint.NetPair
}
// Attach for virtual endpoint bridges the network pair and adds the
// tap interface of the network pair to the hypervisor.
func (endpoint *BridgedMacvlanEndpoint) Attach(h hypervisor) error {
networkLogger().Info("Attaching macvlan endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual ep")
return err
}
return h.addDevice(endpoint, netDev)
}
// Detach for the virtual endpoint tears down the tap and bridge
// created for the veth interface.
func (endpoint *BridgedMacvlanEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// The network namespace would have been deleted at this point
// if it has not been created by virtcontainers.
if !netNsCreated {
return nil
}
networkLogger().Info("Detaching virtual endpoint")
return doNetNS(netNsPath, func(_ ns.NetNS) error {
//return xconnectVMNetwork(&(endpoint.NetPair), false, 0, false, endpoint.EndpointType)
return xconnectVMNetwork(endpoint, false, 0, false)
})
}
// HotAttach for physical endpoint not supported yet
func (endpoint *BridgedMacvlanEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot attach")
}
// HotDetach for physical endpoint not supported yet
func (endpoint *BridgedMacvlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot detach")
}
//Macvtap
// Properties returns the properties of the macvtap interface.
func (endpoint *MacvtapEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// HardwareAddr returns the mac address of the macvtap network interface.
func (endpoint *MacvtapEndpoint) HardwareAddr() string {
return endpoint.EndpointProperties.Iface.HardwareAddr.String()
}
// Name returns name of the macvtap interface.
func (endpoint *MacvtapEndpoint) Name() string {
return endpoint.EndpointProperties.Iface.Name
}
// Type indentifies the endpoint as a macvtap endpoint.
func (endpoint *MacvtapEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties of the macvtap endpoint.
func (endpoint *MacvtapEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// Attach for macvtap endpoint passes macvtap device to the hypervisor.
func (endpoint *MacvtapEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "macvtap").Info("Attaching endpoint")
var err error
endpoint.VMFds, err = createMacvtapFds(endpoint.EndpointProperties.Iface.Index, int(h.hypervisorConfig().NumVCPUs))
if err != nil {
return fmt.Errorf("Could not setup macvtap fds %s: %s", endpoint.EndpointProperties.Iface.Name, err)
}
if !h.hypervisorConfig().DisableVhostNet {
vhostFds, err := createVhostFds(int(h.hypervisorConfig().NumVCPUs))
if err != nil {
return fmt.Errorf("Could not setup vhost fds %s : %s", endpoint.EndpointProperties.Iface.Name, err)
}
endpoint.VhostFds = vhostFds
}
return h.addDevice(endpoint, netDev)
}
// Detach for macvtap endpoint does nothing.
func (endpoint *MacvtapEndpoint) Detach(netNsCreated bool, netNsPath string) error {
networkLogger().WithField("endpoint-type", "macvtap").Info("Detaching endpoint")
return nil
}
// HotAttach for macvtap endpoint not supported yet
func (endpoint *MacvtapEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("MacvtapEndpoint does not support Hot attach")
}
// HotDetach for macvtap endpoint not supported yet
func (endpoint *MacvtapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("MacvtapEndpoint does not support Hot detach")
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *MacvtapEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *MacvtapEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}
// EndpointType identifies the type of the network endpoint.
type EndpointType string
const (
// PhysicalEndpointType is the physical network interface.
PhysicalEndpointType EndpointType = "physical"
// VirtualEndpointType is the virtual network interface.
VirtualEndpointType EndpointType = "virtual"
// VhostUserEndpointType is the vhostuser network interface.
VhostUserEndpointType EndpointType = "vhost-user"
// BridgedMacvlanEndpointType is macvlan network interface.
BridgedMacvlanEndpointType EndpointType = "macvlan"
// MacvtapEndpointType is macvtap network interface.
MacvtapEndpointType EndpointType = "macvtap"
)
// Set sets an endpoint type based on the input string.
func (endpointType *EndpointType) Set(value string) error {
switch value {
case "physical":
*endpointType = PhysicalEndpointType
return nil
case "virtual":
*endpointType = VirtualEndpointType
return nil
case "vhost-user":
*endpointType = VhostUserEndpointType
return nil
case "macvlan":
*endpointType = BridgedMacvlanEndpointType
return nil
case "macvtap":
*endpointType = MacvtapEndpointType
return nil
default:
return fmt.Errorf("Unknown endpoint type %s", value)
}
}
// String converts an endpoint type to a string.
func (endpointType *EndpointType) String() string {
switch *endpointType {
case PhysicalEndpointType:
return string(PhysicalEndpointType)
case VirtualEndpointType:
return string(VirtualEndpointType)
case VhostUserEndpointType:
return string(VhostUserEndpointType)
case BridgedMacvlanEndpointType:
return string(BridgedMacvlanEndpointType)
case MacvtapEndpointType:
return string(MacvtapEndpointType)
default:
return ""
}
}
// NetworkNamespace contains all data related to its network namespace.
type NetworkNamespace struct {
NetNsPath string
@ -1411,60 +866,6 @@ func deleteNetNS(netNSPath string) error {
return nil
}
func createVirtualNetworkEndpoint(idx int, ifName string, interworkingModel NetInterworkingModel) (*VirtualEndpoint, error) {
if idx < 0 {
return &VirtualEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
}
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
if err != nil {
return nil, err
}
endpoint := &VirtualEndpoint{
// TODO This is too specific. We may need to create multiple
// end point types here and then decide how to connect them
// at the time of hypervisor attach and not here
NetPair: netPair,
EndpointType: VirtualEndpointType,
}
if ifName != "" {
endpoint.NetPair.VirtIface.Name = ifName
}
return endpoint, nil
}
func createMacvtapNetworkEndpoint(netInfo NetworkInfo) (*MacvtapEndpoint, error) {
endpoint := &MacvtapEndpoint{
EndpointType: MacvtapEndpointType,
EndpointProperties: netInfo,
}
return endpoint, nil
}
func createBridgedMacvlanNetworkEndpoint(idx int, ifName string, interworkingModel NetInterworkingModel) (*BridgedMacvlanEndpoint, error) {
if idx < 0 {
return &BridgedMacvlanEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
}
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
if err != nil {
return nil, err
}
endpoint := &BridgedMacvlanEndpoint{
NetPair: netPair,
EndpointType: BridgedMacvlanEndpointType,
}
if ifName != "" {
endpoint.NetPair.VirtIface.Name = ifName
}
return endpoint, nil
}
func generateInterfacesAndRoutes(networkNS NetworkNamespace) ([]*grpc.Interface, []*grpc.Route, error) {
if networkNS.NetNsPath == "" {
@ -1723,132 +1124,6 @@ func createEndpoint(netInfo NetworkInfo, idx int, model NetInterworkingModel) (E
return endpoint, err
}
// isPhysicalIface checks if an interface is a physical device.
// We use ethtool here to not rely on device sysfs inside the network namespace.
func isPhysicalIface(ifaceName string) (bool, error) {
if ifaceName == "lo" {
return false, nil
}
ethHandle, err := ethtool.NewEthtool()
if err != nil {
return false, err
}
bus, err := ethHandle.BusInfo(ifaceName)
if err != nil {
return false, nil
}
// Check for a pci bus format
tokens := strings.Split(bus, ":")
if len(tokens) != 3 {
return false, nil
}
return true, nil
}
var sysPCIDevicesPath = "/sys/bus/pci/devices"
func createPhysicalEndpoint(netInfo NetworkInfo) (*PhysicalEndpoint, error) {
// Get ethtool handle to derive driver and bus
ethHandle, err := ethtool.NewEthtool()
if err != nil {
return nil, err
}
// Get BDF
bdf, err := ethHandle.BusInfo(netInfo.Iface.Name)
if err != nil {
return nil, err
}
// Get Driver
driver, err := ethHandle.DriverName(netInfo.Iface.Name)
if err != nil {
return nil, err
}
// Get vendor and device id from pci space (sys/bus/pci/devices/$bdf)
ifaceDevicePath := filepath.Join(sysPCIDevicesPath, bdf, "device")
contents, err := ioutil.ReadFile(ifaceDevicePath)
if err != nil {
return nil, err
}
deviceID := strings.TrimSpace(string(contents))
// Vendor id
ifaceVendorPath := filepath.Join(sysPCIDevicesPath, bdf, "vendor")
contents, err = ioutil.ReadFile(ifaceVendorPath)
if err != nil {
return nil, err
}
vendorID := strings.TrimSpace(string(contents))
vendorDeviceID := fmt.Sprintf("%s %s", vendorID, deviceID)
vendorDeviceID = strings.TrimSpace(vendorDeviceID)
physicalEndpoint := &PhysicalEndpoint{
IfaceName: netInfo.Iface.Name,
HardAddr: netInfo.Iface.HardwareAddr.String(),
VendorDeviceID: vendorDeviceID,
EndpointType: PhysicalEndpointType,
Driver: driver,
BDF: bdf,
}
return physicalEndpoint, nil
}
func bindNICToVFIO(endpoint *PhysicalEndpoint) error {
return drivers.BindDevicetoVFIO(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
}
func bindNICToHost(endpoint *PhysicalEndpoint) error {
return drivers.BindDevicetoHost(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
}
// Long term, this should be made more configurable. For now matching path
// provided by CNM VPP and OVS-DPDK plugins, available at github.com/clearcontainers/vpp and
// github.com/clearcontainers/ovsdpdk. The plugins create the socket on the host system
// using this path.
const hostSocketSearchPath = "/tmp/vhostuser_%s/vhu.sock"
// findVhostUserNetSocketPath checks if an interface is a dummy placeholder
// for a vhost-user socket, and if it is it returns the path to the socket
func findVhostUserNetSocketPath(netInfo NetworkInfo) (string, error) {
if netInfo.Iface.Name == "lo" {
return "", nil
}
// check for socket file existence at known location.
for _, addr := range netInfo.Addrs {
socketPath := fmt.Sprintf(hostSocketSearchPath, addr.IPNet.IP)
if _, err := os.Stat(socketPath); err == nil {
return socketPath, nil
}
}
return "", nil
}
// vhostUserSocketPath returns the path of the socket discovered. This discovery
// will vary depending on the type of vhost-user socket.
// Today only VhostUserNetDevice is supported.
func vhostUserSocketPath(info interface{}) (string, error) {
switch v := info.(type) {
case NetworkInfo:
return findVhostUserNetSocketPath(v)
default:
return "", nil
}
}
// network is the virtcontainers network interface.
// Container network plugins are used to setup virtual network
// between VM netns and the host network physical interface.

View File

@ -0,0 +1,194 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/safchain/ethtool"
)
// PhysicalEndpoint gathers a physical network interface and its properties
type PhysicalEndpoint struct {
IfaceName string
HardAddr string
EndpointProperties NetworkInfo
EndpointType EndpointType
BDF string
Driver string
VendorDeviceID string
PCIAddr string
}
// Properties returns the properties of the physical interface.
func (endpoint *PhysicalEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// HardwareAddr returns the mac address of the physical network interface.
func (endpoint *PhysicalEndpoint) HardwareAddr() string {
return endpoint.HardAddr
}
// Name returns name of the physical interface.
func (endpoint *PhysicalEndpoint) Name() string {
return endpoint.IfaceName
}
// Type indentifies the endpoint as a physical endpoint.
func (endpoint *PhysicalEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *PhysicalEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// SetProperties sets the properties of the physical endpoint.
func (endpoint *PhysicalEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *PhysicalEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}
// Attach for physical endpoint binds the physical network interface to
// vfio-pci and adds device to the hypervisor with vfio-passthrough.
func (endpoint *PhysicalEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "physical").Info("Attaching endpoint")
// Unbind physical interface from host driver and bind to vfio
// so that it can be passed to qemu.
if err := bindNICToVFIO(endpoint); err != nil {
return err
}
// TODO: use device manager as general device management entrance
d := config.VFIODev{
BDF: endpoint.BDF,
}
return h.addDevice(d, vfioDev)
}
// Detach for physical endpoint unbinds the physical network interface from vfio-pci
// and binds it back to the saved host driver.
func (endpoint *PhysicalEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// Bind back the physical network interface to host.
// We need to do this even if a new network namespace has not
// been created by virtcontainers.
networkLogger().WithField("endpoint-type", "physical").Info("Detaching endpoint")
// We do not need to enter the network namespace to bind back the
// physical interface to host driver.
return bindNICToHost(endpoint)
}
// HotAttach for physical endpoint not supported yet
func (endpoint *PhysicalEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("PhysicalEndpoint does not support Hot attach")
}
// HotDetach for physical endpoint not supported yet
func (endpoint *PhysicalEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("PhysicalEndpoint does not support Hot detach")
}
// isPhysicalIface checks if an interface is a physical device.
// We use ethtool here to not rely on device sysfs inside the network namespace.
func isPhysicalIface(ifaceName string) (bool, error) {
if ifaceName == "lo" {
return false, nil
}
ethHandle, err := ethtool.NewEthtool()
if err != nil {
return false, err
}
bus, err := ethHandle.BusInfo(ifaceName)
if err != nil {
return false, nil
}
// Check for a pci bus format
tokens := strings.Split(bus, ":")
if len(tokens) != 3 {
return false, nil
}
return true, nil
}
var sysPCIDevicesPath = "/sys/bus/pci/devices"
func createPhysicalEndpoint(netInfo NetworkInfo) (*PhysicalEndpoint, error) {
// Get ethtool handle to derive driver and bus
ethHandle, err := ethtool.NewEthtool()
if err != nil {
return nil, err
}
// Get BDF
bdf, err := ethHandle.BusInfo(netInfo.Iface.Name)
if err != nil {
return nil, err
}
// Get Driver
driver, err := ethHandle.DriverName(netInfo.Iface.Name)
if err != nil {
return nil, err
}
// Get vendor and device id from pci space (sys/bus/pci/devices/$bdf)
ifaceDevicePath := filepath.Join(sysPCIDevicesPath, bdf, "device")
contents, err := ioutil.ReadFile(ifaceDevicePath)
if err != nil {
return nil, err
}
deviceID := strings.TrimSpace(string(contents))
// Vendor id
ifaceVendorPath := filepath.Join(sysPCIDevicesPath, bdf, "vendor")
contents, err = ioutil.ReadFile(ifaceVendorPath)
if err != nil {
return nil, err
}
vendorID := strings.TrimSpace(string(contents))
vendorDeviceID := fmt.Sprintf("%s %s", vendorID, deviceID)
vendorDeviceID = strings.TrimSpace(vendorDeviceID)
physicalEndpoint := &PhysicalEndpoint{
IfaceName: netInfo.Iface.Name,
HardAddr: netInfo.Iface.HardwareAddr.String(),
VendorDeviceID: vendorDeviceID,
EndpointType: PhysicalEndpointType,
Driver: driver,
BDF: bdf,
}
return physicalEndpoint, nil
}
func bindNICToVFIO(endpoint *PhysicalEndpoint) error {
return drivers.BindDevicetoVFIO(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
}
func bindNICToHost(endpoint *PhysicalEndpoint) error {
return drivers.BindDevicetoHost(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
}

View File

@ -0,0 +1,149 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"encoding/hex"
"fmt"
"os"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/utils"
)
// Long term, this should be made more configurable. For now matching path
// provided by CNM VPP and OVS-DPDK plugins, available at github.com/clearcontainers/vpp and
// github.com/clearcontainers/ovsdpdk. The plugins create the socket on the host system
// using this path.
const hostSocketSearchPath = "/tmp/vhostuser_%s/vhu.sock"
// VhostUserEndpoint represents a vhost-user socket based network interface
type VhostUserEndpoint struct {
// Path to the vhost-user socket on the host system
SocketPath string
// MAC address of the interface
HardAddr string
IfaceName string
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
}
// Properties returns the properties of the interface.
func (endpoint *VhostUserEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the interface.
func (endpoint *VhostUserEndpoint) Name() string {
return endpoint.IfaceName
}
// HardwareAddr returns the mac address of the vhostuser network interface
func (endpoint *VhostUserEndpoint) HardwareAddr() string {
return endpoint.HardAddr
}
// Type indentifies the endpoint as a vhostuser endpoint.
func (endpoint *VhostUserEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// SetProperties sets the properties of the endpoint.
func (endpoint *VhostUserEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VhostUserEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *VhostUserEndpoint) NetworkPair() *NetworkInterfacePair {
return nil
}
// Attach for vhostuser endpoint
func (endpoint *VhostUserEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "vhostuser").Info("Attaching endpoint")
// Generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
d := config.VhostUserDeviceAttrs{
DevID: id,
SocketPath: endpoint.SocketPath,
MacAddress: endpoint.HardAddr,
Type: config.VhostUserNet,
}
return h.addDevice(d, vhostuserDev)
}
// Detach for vhostuser endpoint
func (endpoint *VhostUserEndpoint) Detach(netNsCreated bool, netNsPath string) error {
networkLogger().WithField("endpoint-type", "vhostuser").Info("Detaching endpoint")
return nil
}
// HotAttach for vhostuser endpoint not supported yet
func (endpoint *VhostUserEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("VhostUserEndpoint does not support Hot attach")
}
// 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")
}
// Create a vhostuser endpoint
func createVhostUserEndpoint(netInfo NetworkInfo, socket string) (*VhostUserEndpoint, error) {
vhostUserEndpoint := &VhostUserEndpoint{
SocketPath: socket,
HardAddr: netInfo.Iface.HardwareAddr.String(),
IfaceName: netInfo.Iface.Name,
EndpointType: VhostUserEndpointType,
}
return vhostUserEndpoint, nil
}
// findVhostUserNetSocketPath checks if an interface is a dummy placeholder
// for a vhost-user socket, and if it is it returns the path to the socket
func findVhostUserNetSocketPath(netInfo NetworkInfo) (string, error) {
if netInfo.Iface.Name == "lo" {
return "", nil
}
// check for socket file existence at known location.
for _, addr := range netInfo.Addrs {
socketPath := fmt.Sprintf(hostSocketSearchPath, addr.IPNet.IP)
if _, err := os.Stat(socketPath); err == nil {
return socketPath, nil
}
}
return "", nil
}
// vhostUserSocketPath returns the path of the socket discovered. This discovery
// will vary depending on the type of vhost-user socket.
// Today only VhostUserNetDevice is supported.
func vhostUserSocketPath(info interface{}) (string, error) {
switch v := info.(type) {
case NetworkInfo:
return findVhostUserNetSocketPath(v)
default:
return "", nil
}
}

View File

@ -0,0 +1,144 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"github.com/containernetworking/plugins/pkg/ns"
)
// VirtualEndpoint gathers a network pair and its properties.
type VirtualEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
Physical bool
EndpointType EndpointType
PCIAddr string
}
func createVirtualNetworkEndpoint(idx int, ifName string, interworkingModel NetInterworkingModel) (*VirtualEndpoint, error) {
if idx < 0 {
return &VirtualEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
}
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
if err != nil {
return nil, err
}
endpoint := &VirtualEndpoint{
// TODO This is too specific. We may need to create multiple
// end point types here and then decide how to connect them
// at the time of hypervisor attach and not here
NetPair: netPair,
EndpointType: VirtualEndpointType,
}
if ifName != "" {
endpoint.NetPair.VirtIface.Name = ifName
}
return endpoint, nil
}
// Properties returns properties for the veth interface in the network pair.
func (endpoint *VirtualEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}
// Name returns name of the veth interface in the network pair.
func (endpoint *VirtualEndpoint) Name() string {
return endpoint.NetPair.VirtIface.Name
}
// HardwareAddr returns the mac address that is assigned to the tap interface
// in th network pair.
func (endpoint *VirtualEndpoint) HardwareAddr() string {
return endpoint.NetPair.TAPIface.HardAddr
}
// Type identifies the endpoint as a virtual endpoint.
func (endpoint *VirtualEndpoint) Type() EndpointType {
return endpoint.EndpointType
}
// PciAddr returns the PCI address of the endpoint.
func (endpoint *VirtualEndpoint) PciAddr() string {
return endpoint.PCIAddr
}
// NetworkPair returns the network pair of the endpoint.
func (endpoint *VirtualEndpoint) NetworkPair() *NetworkInterfacePair {
return &endpoint.NetPair
}
// SetProperties sets the properties for the endpoint.
func (endpoint *VirtualEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}
// Attach for virtual endpoint bridges the network pair and adds the
// tap interface of the network pair to the hypervisor.
func (endpoint *VirtualEndpoint) Attach(h hypervisor) error {
networkLogger().WithField("endpoint-type", "virtual").Info("Attaching endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual endpoint")
return err
}
return h.addDevice(endpoint, netDev)
}
// Detach for the virtual endpoint tears down the tap and bridge
// created for the veth interface.
func (endpoint *VirtualEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// The network namespace would have been deleted at this point
// if it has not been created by virtcontainers.
if !netNsCreated {
return nil
}
networkLogger().WithField("endpoint-type", "virtual").Info("Detaching endpoint")
return doNetNS(netNsPath, func(_ ns.NetNS) error {
return xconnectVMNetwork(endpoint, false, 0, false)
})
}
// HotAttach for the virtual endpoint uses hot plug device
func (endpoint *VirtualEndpoint) HotAttach(h hypervisor) error {
networkLogger().Info("Hot attaching virtual endpoint")
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual ep")
return err
}
if _, err := h.hotplugAddDevice(endpoint, netDev); err != nil {
networkLogger().WithError(err).Error("Error attach virtual ep")
return err
}
return nil
}
// HotDetach for the virtual endpoint uses hot pull device
func (endpoint *VirtualEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
if !netNsCreated {
return nil
}
networkLogger().Info("Hot detaching virtual endpoint")
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
return xconnectVMNetwork(endpoint, false, 0, h.hypervisorConfig().DisableVhostNet)
}); err != nil {
networkLogger().WithError(err).Warn("Error un-bridging virtual ep")
}
if _, err := h.hotplugRemoveDevice(endpoint, netDev); err != nil {
networkLogger().WithError(err).Error("Error detach virtual ep")
return err
}
return nil
}