gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/tap_endpoint.go (about)

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