This repository has been archived by the owner on May 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Gabi Beyer
committed
Jul 16, 2019
1 parent
8eb7ce4
commit 1a5fa52
Showing
4 changed files
with
238 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// Copyright (c) 2018 Huawei Corporation | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
package virtcontainers | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
|
||
"github.com/containernetworking/plugins/pkg/ns" | ||
"github.com/vishvananda/netlink" | ||
) | ||
|
||
// 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 | ||
} |