mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-03 18:04:16 +00:00
Merge pull request #1028 from sboeuf/multi_queues
network: Don't assume multiple queues support by default
This commit is contained in:
@@ -84,7 +84,7 @@ func (endpoint *BridgedMacvlanEndpoint) NetworkPair() *NetworkInterfacePair {
|
|||||||
// Attach for virtual endpoint bridges the network pair and adds the
|
// Attach for virtual endpoint bridges the network pair and adds the
|
||||||
// tap interface of the network pair to the hypervisor.
|
// tap interface of the network pair to the hypervisor.
|
||||||
func (endpoint *BridgedMacvlanEndpoint) Attach(h hypervisor) error {
|
func (endpoint *BridgedMacvlanEndpoint) Attach(h hypervisor) error {
|
||||||
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
|
if err := xConnectVMNetwork(endpoint, h); err != nil {
|
||||||
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ func (endpoint *BridgedMacvlanEndpoint) Detach(netNsCreated bool, netNsPath stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
||||||
return xconnectVMNetwork(endpoint, false, 0, false)
|
return xDisconnectVMNetwork(endpoint)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ package virtcontainers
|
|||||||
const (
|
const (
|
||||||
blockDeviceSupport = 1 << iota
|
blockDeviceSupport = 1 << iota
|
||||||
blockDeviceHotplugSupport
|
blockDeviceHotplugSupport
|
||||||
|
multiQueueSupport
|
||||||
)
|
)
|
||||||
|
|
||||||
type capabilities struct {
|
type capabilities struct {
|
||||||
@@ -35,3 +36,14 @@ func (caps *capabilities) isBlockDeviceHotplugSupported() bool {
|
|||||||
func (caps *capabilities) setBlockDeviceHotplugSupport() {
|
func (caps *capabilities) setBlockDeviceHotplugSupport() {
|
||||||
caps.flags |= blockDeviceHotplugSupport
|
caps.flags |= blockDeviceHotplugSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (caps *capabilities) isMultiQueueSupported() bool {
|
||||||
|
if caps.flags&multiQueueSupport != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (caps *capabilities) setMultiQueueSupport() {
|
||||||
|
caps.flags |= multiQueueSupport
|
||||||
|
}
|
||||||
|
@@ -87,7 +87,7 @@ func (endpoint *IPVlanEndpoint) NetworkPair() *NetworkInterfacePair {
|
|||||||
// Attach for virtual endpoint bridges the network pair and adds the
|
// Attach for virtual endpoint bridges the network pair and adds the
|
||||||
// tap interface of the network pair to the hypervisor.
|
// tap interface of the network pair to the hypervisor.
|
||||||
func (endpoint *IPVlanEndpoint) Attach(h hypervisor) error {
|
func (endpoint *IPVlanEndpoint) Attach(h hypervisor) error {
|
||||||
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
|
if err := xConnectVMNetwork(endpoint, h); err != nil {
|
||||||
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ func (endpoint *IPVlanEndpoint) Detach(netNsCreated bool, netNsPath string) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
||||||
return xconnectVMNetwork(endpoint, false, 0, false)
|
return xDisconnectVMNetwork(endpoint)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -396,7 +396,7 @@ func newNetwork(networkType NetworkModel) network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createLink(netHandle *netlink.Handle, name string, expectedLink netlink.Link, numCPUs int) (netlink.Link, []*os.File, error) {
|
func createLink(netHandle *netlink.Handle, name string, expectedLink netlink.Link, queues int) (netlink.Link, []*os.File, error) {
|
||||||
var newLink netlink.Link
|
var newLink netlink.Link
|
||||||
var fds []*os.File
|
var fds []*os.File
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ func createLink(netHandle *netlink.Handle, name string, expectedLink netlink.Lin
|
|||||||
newLink = &netlink.Tuntap{
|
newLink = &netlink.Tuntap{
|
||||||
LinkAttrs: netlink.LinkAttrs{Name: name},
|
LinkAttrs: netlink.LinkAttrs{Name: name},
|
||||||
Mode: netlink.TUNTAP_MODE_TAP,
|
Mode: netlink.TUNTAP_MODE_TAP,
|
||||||
Queues: numCPUs,
|
Queues: queues,
|
||||||
Flags: netlink.TUNTAP_MULTI_QUEUE_DEFAULTS | netlink.TUNTAP_VNET_HDR,
|
Flags: netlink.TUNTAP_MULTI_QUEUE_DEFAULTS | netlink.TUNTAP_VNET_HDR,
|
||||||
}
|
}
|
||||||
case (&netlink.Macvtap{}).Type():
|
case (&netlink.Macvtap{}).Type():
|
||||||
@@ -501,30 +501,50 @@ func getLinkByName(netHandle *netlink.Handle, name string, expectedLink netlink.
|
|||||||
return nil, fmt.Errorf("Incorrect link type %s, expecting %s", link.Type(), expectedLink.Type())
|
return nil, fmt.Errorf("Incorrect link type %s, expecting %s", link.Type(), expectedLink.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
// The endpoint type should dictate how the connection needs to be made
|
// The endpoint type should dictate how the connection needs to happen.
|
||||||
func xconnectVMNetwork(endpoint Endpoint, connect bool, numCPUs uint32, disableVhostNet bool) error {
|
func xConnectVMNetwork(endpoint Endpoint, h hypervisor) error {
|
||||||
|
netPair := endpoint.NetworkPair()
|
||||||
|
|
||||||
|
queues := 0
|
||||||
|
caps := h.capabilities()
|
||||||
|
if caps.isMultiQueueSupported() {
|
||||||
|
queues = int(h.hypervisorConfig().NumVCPUs)
|
||||||
|
}
|
||||||
|
|
||||||
|
disableVhostNet := h.hypervisorConfig().DisableVhostNet
|
||||||
|
|
||||||
|
if netPair.NetInterworkingModel == NetXConnectDefaultModel {
|
||||||
|
netPair.NetInterworkingModel = DefaultNetInterworkingModel
|
||||||
|
}
|
||||||
|
|
||||||
|
switch netPair.NetInterworkingModel {
|
||||||
|
case NetXConnectBridgedModel:
|
||||||
|
return bridgeNetworkPair(endpoint, queues, disableVhostNet)
|
||||||
|
case NetXConnectMacVtapModel:
|
||||||
|
return tapNetworkPair(endpoint, queues, disableVhostNet)
|
||||||
|
case NetXConnectTCFilterModel:
|
||||||
|
return setupTCFiltering(endpoint, queues, disableVhostNet)
|
||||||
|
case NetXConnectEnlightenedModel:
|
||||||
|
return fmt.Errorf("Unsupported networking model")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Invalid internetworking model")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The endpoint type should dictate how the disconnection needs to happen.
|
||||||
|
func xDisconnectVMNetwork(endpoint Endpoint) error {
|
||||||
netPair := endpoint.NetworkPair()
|
netPair := endpoint.NetworkPair()
|
||||||
|
|
||||||
if netPair.NetInterworkingModel == NetXConnectDefaultModel {
|
if netPair.NetInterworkingModel == NetXConnectDefaultModel {
|
||||||
netPair.NetInterworkingModel = DefaultNetInterworkingModel
|
netPair.NetInterworkingModel = DefaultNetInterworkingModel
|
||||||
}
|
}
|
||||||
|
|
||||||
switch netPair.NetInterworkingModel {
|
switch netPair.NetInterworkingModel {
|
||||||
case NetXConnectBridgedModel:
|
case NetXConnectBridgedModel:
|
||||||
netPair.NetInterworkingModel = NetXConnectBridgedModel
|
|
||||||
if connect {
|
|
||||||
return bridgeNetworkPair(endpoint, numCPUs, disableVhostNet)
|
|
||||||
}
|
|
||||||
return unBridgeNetworkPair(endpoint)
|
return unBridgeNetworkPair(endpoint)
|
||||||
case NetXConnectMacVtapModel:
|
case NetXConnectMacVtapModel:
|
||||||
netPair.NetInterworkingModel = NetXConnectMacVtapModel
|
|
||||||
if connect {
|
|
||||||
return tapNetworkPair(endpoint, numCPUs, disableVhostNet)
|
|
||||||
}
|
|
||||||
return untapNetworkPair(endpoint)
|
return untapNetworkPair(endpoint)
|
||||||
case NetXConnectTCFilterModel:
|
case NetXConnectTCFilterModel:
|
||||||
if connect {
|
|
||||||
return setupTCFiltering(endpoint, numCPUs, disableVhostNet)
|
|
||||||
}
|
|
||||||
return removeTCFiltering(endpoint)
|
return removeTCFiltering(endpoint)
|
||||||
case NetXConnectEnlightenedModel:
|
case NetXConnectEnlightenedModel:
|
||||||
return fmt.Errorf("Unsupported networking model")
|
return fmt.Errorf("Unsupported networking model")
|
||||||
@@ -573,10 +593,10 @@ const linkRange = 0xFFFF // This will allow upto 2^16 containers
|
|||||||
const linkRetries = 128 // The numbers of time we try to find a non conflicting index
|
const linkRetries = 128 // The numbers of time we try to find a non conflicting index
|
||||||
const macvtapWorkaround = true
|
const macvtapWorkaround = true
|
||||||
|
|
||||||
func createMacVtap(netHandle *netlink.Handle, name string, link netlink.Link, numCPUs int) (taplink netlink.Link, err error) {
|
func createMacVtap(netHandle *netlink.Handle, name string, link netlink.Link, queues int) (taplink netlink.Link, err error) {
|
||||||
|
|
||||||
if !macvtapWorkaround {
|
if !macvtapWorkaround {
|
||||||
taplink, _, err = createLink(netHandle, name, link, numCPUs)
|
taplink, _, err = createLink(netHandle, name, link, queues)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,7 +605,7 @@ func createMacVtap(netHandle *netlink.Handle, name string, link netlink.Link, nu
|
|||||||
for i := 0; i < linkRetries; i++ {
|
for i := 0; i < linkRetries; i++ {
|
||||||
index := hostLinkOffset + (r.Int() & linkRange)
|
index := hostLinkOffset + (r.Int() & linkRange)
|
||||||
link.Attrs().Index = index
|
link.Attrs().Index = index
|
||||||
taplink, _, err = createLink(netHandle, name, link, numCPUs)
|
taplink, _, err = createLink(netHandle, name, link, queues)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -612,7 +632,7 @@ func setIPs(link netlink.Link, addrs []netlink.Addr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tapNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) error {
|
func tapNetworkPair(endpoint Endpoint, queues int, disableVhostNet bool) error {
|
||||||
netHandle, err := netlink.NewHandle()
|
netHandle, err := netlink.NewHandle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -638,7 +658,7 @@ func tapNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) err
|
|||||||
ParentIndex: attrs.Index,
|
ParentIndex: attrs.Index,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, int(numCPUs))
|
}, queues)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not create TAP interface: %s", err)
|
return fmt.Errorf("Could not create TAP interface: %s", err)
|
||||||
@@ -690,13 +710,13 @@ func tapNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) err
|
|||||||
|
|
||||||
// Note: The underlying interfaces need to be up prior to fd creation.
|
// Note: The underlying interfaces need to be up prior to fd creation.
|
||||||
|
|
||||||
netPair.VMFds, err = createMacvtapFds(tapLink.Attrs().Index, int(numCPUs))
|
netPair.VMFds, err = createMacvtapFds(tapLink.Attrs().Index, queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not setup macvtap fds %s: %s", netPair.TAPIface, err)
|
return fmt.Errorf("Could not setup macvtap fds %s: %s", netPair.TAPIface, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !disableVhostNet {
|
if !disableVhostNet {
|
||||||
vhostFds, err := createVhostFds(int(numCPUs))
|
vhostFds, err := createVhostFds(queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
||||||
}
|
}
|
||||||
@@ -706,7 +726,7 @@ func tapNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bridgeNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) error {
|
func bridgeNetworkPair(endpoint Endpoint, queues int, disableVhostNet bool) error {
|
||||||
netHandle, err := netlink.NewHandle()
|
netHandle, err := netlink.NewHandle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -715,14 +735,14 @@ func bridgeNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool)
|
|||||||
|
|
||||||
netPair := endpoint.NetworkPair()
|
netPair := endpoint.NetworkPair()
|
||||||
|
|
||||||
tapLink, fds, err := createLink(netHandle, netPair.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
|
tapLink, fds, err := createLink(netHandle, netPair.TAPIface.Name, &netlink.Tuntap{}, queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not create TAP interface: %s", err)
|
return fmt.Errorf("Could not create TAP interface: %s", err)
|
||||||
}
|
}
|
||||||
netPair.VMFds = fds
|
netPair.VMFds = fds
|
||||||
|
|
||||||
if !disableVhostNet {
|
if !disableVhostNet {
|
||||||
vhostFds, err := createVhostFds(int(numCPUs))
|
vhostFds, err := createVhostFds(queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
||||||
}
|
}
|
||||||
@@ -760,7 +780,7 @@ func bridgeNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mcastSnoop := false
|
mcastSnoop := false
|
||||||
bridgeLink, _, err := createLink(netHandle, netPair.Name, &netlink.Bridge{MulticastSnooping: &mcastSnoop}, int(numCPUs))
|
bridgeLink, _, err := createLink(netHandle, netPair.Name, &netlink.Bridge{MulticastSnooping: &mcastSnoop}, queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not create bridge: %s", err)
|
return fmt.Errorf("Could not create bridge: %s", err)
|
||||||
}
|
}
|
||||||
@@ -790,7 +810,7 @@ func bridgeNetworkPair(endpoint Endpoint, numCPUs uint32, disableVhostNet bool)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupTCFiltering(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) error {
|
func setupTCFiltering(endpoint Endpoint, queues int, disableVhostNet bool) error {
|
||||||
netHandle, err := netlink.NewHandle()
|
netHandle, err := netlink.NewHandle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -799,14 +819,14 @@ func setupTCFiltering(endpoint Endpoint, numCPUs uint32, disableVhostNet bool) e
|
|||||||
|
|
||||||
netPair := endpoint.NetworkPair()
|
netPair := endpoint.NetworkPair()
|
||||||
|
|
||||||
tapLink, fds, err := createLink(netHandle, netPair.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
|
tapLink, fds, err := createLink(netHandle, netPair.TAPIface.Name, &netlink.Tuntap{}, queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not create TAP interface: %s", err)
|
return fmt.Errorf("Could not create TAP interface: %s", err)
|
||||||
}
|
}
|
||||||
netPair.VMFds = fds
|
netPair.VMFds = fds
|
||||||
|
|
||||||
if !disableVhostNet {
|
if !disableVhostNet {
|
||||||
vhostFds, err := createVhostFds(int(numCPUs))
|
vhostFds, err := createVhostFds(queues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
return fmt.Errorf("Could not setup vhost fds %s : %s", netPair.VirtIface.Name, err)
|
||||||
}
|
}
|
||||||
|
@@ -108,6 +108,8 @@ func (q *qemuAmd64) capabilities() capabilities {
|
|||||||
caps.setBlockDeviceHotplugSupport()
|
caps.setBlockDeviceHotplugSupport()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
caps.setMultiQueueSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -237,6 +237,7 @@ func (q *qemuArchBase) kernelParameters(debug bool) []Param {
|
|||||||
func (q *qemuArchBase) capabilities() capabilities {
|
func (q *qemuArchBase) capabilities() capabilities {
|
||||||
var caps capabilities
|
var caps capabilities
|
||||||
caps.setBlockDeviceHotplugSupport()
|
caps.setBlockDeviceHotplugSupport()
|
||||||
|
caps.setMultiQueueSupport()
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -94,6 +94,8 @@ func (q *qemuPPC64le) capabilities() capabilities {
|
|||||||
caps.setBlockDeviceHotplugSupport()
|
caps.setBlockDeviceHotplugSupport()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
caps.setMultiQueueSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -88,7 +88,7 @@ func (endpoint *VethEndpoint) SetProperties(properties NetworkInfo) {
|
|||||||
// Attach for veth endpoint bridges the network pair and adds the
|
// Attach for veth endpoint bridges the network pair and adds the
|
||||||
// tap interface of the network pair to the hypervisor.
|
// tap interface of the network pair to the hypervisor.
|
||||||
func (endpoint *VethEndpoint) Attach(h hypervisor) error {
|
func (endpoint *VethEndpoint) Attach(h hypervisor) error {
|
||||||
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
|
if err := xConnectVMNetwork(endpoint, h); err != nil {
|
||||||
networkLogger().WithError(err).Error("Error bridging virtual endpoint")
|
networkLogger().WithError(err).Error("Error bridging virtual endpoint")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -106,13 +106,13 @@ func (endpoint *VethEndpoint) Detach(netNsCreated bool, netNsPath string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
||||||
return xconnectVMNetwork(endpoint, false, 0, false)
|
return xDisconnectVMNetwork(endpoint)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// HotAttach for the veth endpoint uses hot plug device
|
// HotAttach for the veth endpoint uses hot plug device
|
||||||
func (endpoint *VethEndpoint) HotAttach(h hypervisor) error {
|
func (endpoint *VethEndpoint) HotAttach(h hypervisor) error {
|
||||||
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
|
if err := xConnectVMNetwork(endpoint, h); err != nil {
|
||||||
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
networkLogger().WithError(err).Error("Error bridging virtual ep")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ func (endpoint *VethEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
|
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
|
||||||
return xconnectVMNetwork(endpoint, false, 0, h.hypervisorConfig().DisableVhostNet)
|
return xDisconnectVMNetwork(endpoint)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
networkLogger().WithError(err).Warn("Error un-bridging virtual ep")
|
networkLogger().WithError(err).Warn("Error un-bridging virtual ep")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user