mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-28 20:15:51 +00:00
The tuntap network device is for tuntap interfaces to connect to the container. A specific use case is the slirp4netns tap interface for rootless kata-runtime. Fixes: #1878 Signed-off-by: Gabi Beyer <gabrielle.n.beyer@intel.com>
215 lines
6.5 KiB
Go
215 lines
6.5 KiB
Go
// Copyright (c) 2018 Huawei Corporation
|
|
// Copyright (c) 2019 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/containernetworking/plugins/pkg/ns"
|
|
"github.com/vishvananda/netlink"
|
|
|
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
|
)
|
|
|
|
// TuntapEndpoint represents just a tap endpoint
|
|
type TuntapEndpoint struct {
|
|
NetPair NetworkInterfacePair
|
|
TuntapInterface TuntapInterface
|
|
EndpointProperties NetworkInfo
|
|
EndpointType EndpointType
|
|
PCIAddr string
|
|
}
|
|
|
|
// Properties returns the properties of the tap interface.
|
|
func (endpoint *TuntapEndpoint) Properties() NetworkInfo {
|
|
return endpoint.EndpointProperties
|
|
}
|
|
|
|
// Name returns name of the tap interface in the network pair.
|
|
func (endpoint *TuntapEndpoint) Name() string {
|
|
return endpoint.TuntapInterface.Name
|
|
}
|
|
|
|
// HardwareAddr returns the mac address that is assigned to the tap interface
|
|
func (endpoint *TuntapEndpoint) HardwareAddr() string {
|
|
return endpoint.TuntapInterface.TAPIface.HardAddr
|
|
}
|
|
|
|
// Type identifies the endpoint as a tap endpoint.
|
|
func (endpoint *TuntapEndpoint) Type() EndpointType {
|
|
return endpoint.EndpointType
|
|
}
|
|
|
|
// PciAddr returns the PCI address of the endpoint.
|
|
func (endpoint *TuntapEndpoint) PciAddr() string {
|
|
return endpoint.PCIAddr
|
|
}
|
|
|
|
// SetPciAddr sets the PCI address of the endpoint.
|
|
func (endpoint *TuntapEndpoint) SetPciAddr(pciAddr string) {
|
|
endpoint.PCIAddr = pciAddr
|
|
}
|
|
|
|
// NetworkPair returns the network pair of the endpoint.
|
|
func (endpoint *TuntapEndpoint) NetworkPair() *NetworkInterfacePair {
|
|
return &endpoint.NetPair
|
|
}
|
|
|
|
// SetProperties sets the properties for the endpoint.
|
|
func (endpoint *TuntapEndpoint) SetProperties(properties NetworkInfo) {
|
|
endpoint.EndpointProperties = properties
|
|
}
|
|
|
|
// Attach for tap endpoint adds the tap interface to the hypervisor.
|
|
func (endpoint *TuntapEndpoint) Attach(h hypervisor) error {
|
|
if err := xConnectVMNetwork(endpoint, h); err != nil {
|
|
networkLogger().WithError(err).Error("Error bridging virtual endpoint")
|
|
return err
|
|
}
|
|
return h.addDevice(endpoint, netDev)
|
|
}
|
|
|
|
// Detach for the tap endpoint tears down the tap
|
|
func (endpoint *TuntapEndpoint) Detach(netNsCreated bool, netNsPath string) error {
|
|
if !netNsCreated && netNsPath != "" {
|
|
return nil
|
|
}
|
|
|
|
networkLogger().WithField("endpoint-type", TuntapEndpointType).Info("Detaching endpoint")
|
|
return doNetNS(netNsPath, func(_ ns.NetNS) error {
|
|
return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name)
|
|
})
|
|
}
|
|
|
|
// HotAttach for the tap endpoint uses hot plug device
|
|
func (endpoint *TuntapEndpoint) HotAttach(h hypervisor) error {
|
|
networkLogger().Info("Hot attaching tap endpoint")
|
|
if err := tuntapNetwork(endpoint, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
|
|
networkLogger().WithError(err).Error("Error bridging tap ep")
|
|
return err
|
|
}
|
|
|
|
if _, err := h.hotplugAddDevice(endpoint, netDev); err != nil {
|
|
networkLogger().WithError(err).Error("Error attach tap ep")
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HotDetach for the tap endpoint uses hot pull device
|
|
func (endpoint *TuntapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
|
networkLogger().Info("Hot detaching tap endpoint")
|
|
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
|
|
return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name)
|
|
}); err != nil {
|
|
networkLogger().WithError(err).Warn("Error un-bridging tap ep")
|
|
}
|
|
|
|
if _, err := h.hotplugRemoveDevice(endpoint, netDev); err != nil {
|
|
networkLogger().WithError(err).Error("Error detach tap ep")
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func createTuntapNetworkEndpoint(idx int, ifName string, hwName net.HardwareAddr, internetworkingModel NetInterworkingModel) (*TuntapEndpoint, error) {
|
|
if idx < 0 {
|
|
return &TuntapEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
|
|
}
|
|
|
|
netPair, err := createNetworkInterfacePair(idx, ifName, internetworkingModel)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpoint := &TuntapEndpoint{
|
|
NetPair: netPair,
|
|
TuntapInterface: TuntapInterface{
|
|
Name: fmt.Sprintf("eth%d", idx),
|
|
TAPIface: NetworkInterface{
|
|
Name: fmt.Sprintf("tap%d_kata", idx),
|
|
HardAddr: fmt.Sprintf("%s", hwName), //nolint:gosimple
|
|
},
|
|
},
|
|
EndpointType: TuntapEndpointType,
|
|
}
|
|
|
|
if ifName != "" {
|
|
endpoint.TuntapInterface.Name = ifName
|
|
}
|
|
|
|
return endpoint, nil
|
|
}
|
|
|
|
func tuntapNetwork(endpoint *TuntapEndpoint, numCPUs uint32, disableVhostNet bool) error {
|
|
netHandle, err := netlink.NewHandle()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer netHandle.Delete()
|
|
|
|
tapLink, _, err := createLink(netHandle, endpoint.TuntapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
|
|
if err != nil {
|
|
return fmt.Errorf("Could not create TAP interface: %s", err)
|
|
}
|
|
linkAttrs := endpoint.Properties().Iface.LinkAttrs
|
|
|
|
// Save the MAC address to the TAP so that it can later be used
|
|
// to build the QMP command line. This MAC address has to be
|
|
// the one inside the VM in order to avoid any firewall issues. The
|
|
// bridge created by the network plugin on the host actually expects
|
|
// to see traffic from this MAC address and not another one.
|
|
endpoint.TuntapInterface.TAPIface.HardAddr = linkAttrs.HardwareAddr.String()
|
|
if err := netHandle.LinkSetMTU(tapLink, linkAttrs.MTU); err != nil {
|
|
return fmt.Errorf("Could not set TAP MTU %d: %s", linkAttrs.MTU, err)
|
|
}
|
|
if err := netHandle.LinkSetUp(tapLink); err != nil {
|
|
return fmt.Errorf("Could not enable TAP %s: %s", endpoint.TuntapInterface.Name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func unTuntapNetwork(name string) error {
|
|
netHandle, err := netlink.NewHandle()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer netHandle.Delete()
|
|
tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{})
|
|
if err != nil {
|
|
return fmt.Errorf("Could not get TAP interface: %s", err)
|
|
}
|
|
if err := netHandle.LinkSetDown(tapLink); err != nil {
|
|
return fmt.Errorf("Could not disable TAP %s: %s", name, err)
|
|
}
|
|
if err := netHandle.LinkDel(tapLink); err != nil {
|
|
return fmt.Errorf("Could not remove TAP %s: %s", name, err)
|
|
}
|
|
return nil
|
|
|
|
}
|
|
func (endpoint *TuntapEndpoint) save() persistapi.NetworkEndpoint {
|
|
tuntapif := saveTuntapIf(&endpoint.TuntapInterface)
|
|
|
|
return persistapi.NetworkEndpoint{
|
|
Type: string(endpoint.Type()),
|
|
Tuntap: &persistapi.TuntapEndpoint{
|
|
TuntapInterface: *tuntapif,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (endpoint *TuntapEndpoint) load(s persistapi.NetworkEndpoint) {
|
|
endpoint.EndpointType = TuntapEndpointType
|
|
|
|
if s.Tuntap != nil {
|
|
tuntapif := loadTuntapIf(&s.Tuntap.TuntapInterface)
|
|
endpoint.TuntapInterface = *tuntapif
|
|
}
|
|
}
|