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