github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/tuntap_endpoint.go (about)

     1  // Copyright (c) 2018 Huawei Corporation
     2  // Copyright (c) 2019 Intel Corporation
     3  //
     4  // SPDX-License-Identifier: Apache-2.0
     5  //
     6  
     7  package virtcontainers
     8  
     9  import (
    10  	"fmt"
    11  	"net"
    12  
    13  	"github.com/containernetworking/plugins/pkg/ns"
    14  	"github.com/vishvananda/netlink"
    15  
    16  	persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
    17  	vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
    18  )
    19  
    20  // TuntapEndpoint represents just a tap endpoint
    21  type TuntapEndpoint struct {
    22  	NetPair            NetworkInterfacePair
    23  	TuntapInterface    TuntapInterface
    24  	EndpointProperties NetworkInfo
    25  	EndpointType       EndpointType
    26  	PCIPath            vcTypes.PciPath
    27  }
    28  
    29  // Properties returns the properties of the tap interface.
    30  func (endpoint *TuntapEndpoint) Properties() NetworkInfo {
    31  	return endpoint.EndpointProperties
    32  }
    33  
    34  // Name returns name of the tap interface in the network pair.
    35  func (endpoint *TuntapEndpoint) Name() string {
    36  	return endpoint.TuntapInterface.Name
    37  }
    38  
    39  // HardwareAddr returns the mac address that is assigned to the tap interface
    40  func (endpoint *TuntapEndpoint) HardwareAddr() string {
    41  	return endpoint.TuntapInterface.TAPIface.HardAddr
    42  }
    43  
    44  // Type identifies the endpoint as a tap endpoint.
    45  func (endpoint *TuntapEndpoint) Type() EndpointType {
    46  	return endpoint.EndpointType
    47  }
    48  
    49  // PciPath returns the PCI path of the endpoint.
    50  func (endpoint *TuntapEndpoint) PciPath() vcTypes.PciPath {
    51  	return endpoint.PCIPath
    52  }
    53  
    54  // SetPciPath sets the PCI path of the endpoint.
    55  func (endpoint *TuntapEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
    56  	endpoint.PCIPath = pciPath
    57  }
    58  
    59  // NetworkPair returns the network pair of the endpoint.
    60  func (endpoint *TuntapEndpoint) NetworkPair() *NetworkInterfacePair {
    61  	return &endpoint.NetPair
    62  }
    63  
    64  // SetProperties sets the properties for the endpoint.
    65  func (endpoint *TuntapEndpoint) SetProperties(properties NetworkInfo) {
    66  	endpoint.EndpointProperties = properties
    67  }
    68  
    69  // Attach for tap endpoint adds the tap interface to the hypervisor.
    70  func (endpoint *TuntapEndpoint) Attach(s *Sandbox) error {
    71  	h := s.hypervisor
    72  	if err := xConnectVMNetwork(endpoint, h); err != nil {
    73  		networkLogger().WithError(err).Error("Error bridging virtual endpoint")
    74  		return err
    75  	}
    76  	return h.addDevice(endpoint, netDev)
    77  }
    78  
    79  // Detach for the tap endpoint tears down the tap
    80  func (endpoint *TuntapEndpoint) Detach(netNsCreated bool, netNsPath string) error {
    81  	if !netNsCreated && netNsPath != "" {
    82  		return nil
    83  	}
    84  
    85  	networkLogger().WithField("endpoint-type", TuntapEndpointType).Info("Detaching endpoint")
    86  	return doNetNS(netNsPath, func(_ ns.NetNS) error {
    87  		return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name)
    88  	})
    89  }
    90  
    91  // HotAttach for the tap endpoint uses hot plug device
    92  func (endpoint *TuntapEndpoint) HotAttach(h hypervisor) error {
    93  	networkLogger().Info("Hot attaching tap endpoint")
    94  	if err := tuntapNetwork(endpoint, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
    95  		networkLogger().WithError(err).Error("Error bridging tap ep")
    96  		return err
    97  	}
    98  
    99  	if _, err := h.hotplugAddDevice(endpoint, netDev); err != nil {
   100  		networkLogger().WithError(err).Error("Error attach tap ep")
   101  		return err
   102  	}
   103  	return nil
   104  }
   105  
   106  // HotDetach for the tap endpoint uses hot pull device
   107  func (endpoint *TuntapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
   108  	networkLogger().Info("Hot detaching tap endpoint")
   109  	if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
   110  		return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name)
   111  	}); err != nil {
   112  		networkLogger().WithError(err).Warn("Error un-bridging tap ep")
   113  	}
   114  
   115  	if _, err := h.hotplugRemoveDevice(endpoint, netDev); err != nil {
   116  		networkLogger().WithError(err).Error("Error detach tap ep")
   117  		return err
   118  	}
   119  	return nil
   120  }
   121  
   122  func createTuntapNetworkEndpoint(idx int, ifName string, hwName net.HardwareAddr, internetworkingModel NetInterworkingModel) (*TuntapEndpoint, error) {
   123  	if idx < 0 {
   124  		return &TuntapEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
   125  	}
   126  
   127  	netPair, err := createNetworkInterfacePair(idx, ifName, internetworkingModel)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	endpoint := &TuntapEndpoint{
   133  		NetPair: netPair,
   134  		TuntapInterface: TuntapInterface{
   135  			Name: fmt.Sprintf("eth%d", idx),
   136  			TAPIface: NetworkInterface{
   137  				Name:     fmt.Sprintf("tap%d_kata", idx),
   138  				HardAddr: fmt.Sprintf("%s", hwName), //nolint:gosimple
   139  			},
   140  		},
   141  		EndpointType: TuntapEndpointType,
   142  	}
   143  
   144  	if ifName != "" {
   145  		endpoint.TuntapInterface.Name = ifName
   146  	}
   147  
   148  	return endpoint, nil
   149  }
   150  
   151  func tuntapNetwork(endpoint *TuntapEndpoint, numCPUs uint32, disableVhostNet bool) error {
   152  	netHandle, err := netlink.NewHandle()
   153  	if err != nil {
   154  		return err
   155  	}
   156  	defer netHandle.Delete()
   157  
   158  	tapLink, _, err := createLink(netHandle, endpoint.TuntapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
   159  	if err != nil {
   160  		return fmt.Errorf("Could not create TAP interface: %s", err)
   161  	}
   162  	linkAttrs := endpoint.Properties().Iface.LinkAttrs
   163  
   164  	// Save the MAC address to the TAP so that it can later be used
   165  	// to build the QMP command line. This MAC address has to be
   166  	// the one inside the VM in order to avoid any firewall issues. The
   167  	// bridge created by the network plugin on the host actually expects
   168  	// to see traffic from this MAC address and not another one.
   169  	endpoint.TuntapInterface.TAPIface.HardAddr = linkAttrs.HardwareAddr.String()
   170  	if err := netHandle.LinkSetMTU(tapLink, linkAttrs.MTU); err != nil {
   171  		return fmt.Errorf("Could not set TAP MTU %d: %s", linkAttrs.MTU, err)
   172  	}
   173  	if err := netHandle.LinkSetUp(tapLink); err != nil {
   174  		return fmt.Errorf("Could not enable TAP %s: %s", endpoint.TuntapInterface.Name, err)
   175  	}
   176  	return nil
   177  }
   178  
   179  func unTuntapNetwork(name string) error {
   180  	netHandle, err := netlink.NewHandle()
   181  	if err != nil {
   182  		return err
   183  	}
   184  	defer netHandle.Delete()
   185  	tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{})
   186  	if err != nil {
   187  		return fmt.Errorf("Could not get TAP interface: %s", err)
   188  	}
   189  	if err := netHandle.LinkSetDown(tapLink); err != nil {
   190  		return fmt.Errorf("Could not disable TAP %s: %s", name, err)
   191  	}
   192  	if err := netHandle.LinkDel(tapLink); err != nil {
   193  		return fmt.Errorf("Could not remove TAP %s: %s", name, err)
   194  	}
   195  	return nil
   196  
   197  }
   198  func (endpoint *TuntapEndpoint) save() persistapi.NetworkEndpoint {
   199  	tuntapif := saveTuntapIf(&endpoint.TuntapInterface)
   200  
   201  	return persistapi.NetworkEndpoint{
   202  		Type: string(endpoint.Type()),
   203  		Tuntap: &persistapi.TuntapEndpoint{
   204  			TuntapInterface: *tuntapif,
   205  		},
   206  	}
   207  }
   208  
   209  func (endpoint *TuntapEndpoint) load(s persistapi.NetworkEndpoint) {
   210  	endpoint.EndpointType = TuntapEndpointType
   211  
   212  	if s.Tuntap != nil {
   213  		tuntapif := loadTuntapIf(&s.Tuntap.TuntapInterface)
   214  		endpoint.TuntapInterface = *tuntapif
   215  	}
   216  }