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

     1  // Copyright (c) 2018 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package virtcontainers
     7  
     8  import (
     9  	"encoding/hex"
    10  	"fmt"
    11  	"os"
    12  
    13  	"github.com/kata-containers/runtime/virtcontainers/device/config"
    14  	persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
    15  	vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
    16  	"github.com/kata-containers/runtime/virtcontainers/utils"
    17  )
    18  
    19  // Long term, this should be made more configurable.  For now matching path
    20  // provided by CNM VPP and OVS-DPDK plugins, available at github.com/clearcontainers/vpp and
    21  // github.com/clearcontainers/ovsdpdk.  The plugins create the socket on the host system
    22  // using this path.
    23  const hostSocketSearchPath = "/tmp/vhostuser_%s/vhu.sock"
    24  
    25  // VhostUserEndpoint represents a vhost-user socket based network interface
    26  type VhostUserEndpoint struct {
    27  	// Path to the vhost-user socket on the host system
    28  	SocketPath string
    29  	// MAC address of the interface
    30  	HardAddr           string
    31  	IfaceName          string
    32  	EndpointProperties NetworkInfo
    33  	EndpointType       EndpointType
    34  	PCIPath            vcTypes.PciPath
    35  }
    36  
    37  // Properties returns the properties of the interface.
    38  func (endpoint *VhostUserEndpoint) Properties() NetworkInfo {
    39  	return endpoint.EndpointProperties
    40  }
    41  
    42  // Name returns name of the interface.
    43  func (endpoint *VhostUserEndpoint) Name() string {
    44  	return endpoint.IfaceName
    45  }
    46  
    47  // HardwareAddr returns the mac address of the vhostuser network interface
    48  func (endpoint *VhostUserEndpoint) HardwareAddr() string {
    49  	return endpoint.HardAddr
    50  }
    51  
    52  // Type indentifies the endpoint as a vhostuser endpoint.
    53  func (endpoint *VhostUserEndpoint) Type() EndpointType {
    54  	return endpoint.EndpointType
    55  }
    56  
    57  // SetProperties sets the properties of the endpoint.
    58  func (endpoint *VhostUserEndpoint) SetProperties(properties NetworkInfo) {
    59  	endpoint.EndpointProperties = properties
    60  }
    61  
    62  // PciPath returns the PCI path of the endpoint.
    63  func (endpoint *VhostUserEndpoint) PciPath() vcTypes.PciPath {
    64  	return endpoint.PCIPath
    65  }
    66  
    67  // SetPciPath sets the PCI path of the endpoint.
    68  func (endpoint *VhostUserEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
    69  	endpoint.PCIPath = pciPath
    70  }
    71  
    72  // NetworkPair returns the network pair of the endpoint.
    73  func (endpoint *VhostUserEndpoint) NetworkPair() *NetworkInterfacePair {
    74  	return nil
    75  }
    76  
    77  // Attach for vhostuser endpoint
    78  func (endpoint *VhostUserEndpoint) Attach(s *Sandbox) error {
    79  	// Generate a unique ID to be used for hypervisor commandline fields
    80  	randBytes, err := utils.GenerateRandomBytes(8)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	id := hex.EncodeToString(randBytes)
    85  
    86  	d := config.VhostUserDeviceAttrs{
    87  		DevID:      id,
    88  		SocketPath: endpoint.SocketPath,
    89  		MacAddress: endpoint.HardAddr,
    90  		Type:       config.VhostUserNet,
    91  	}
    92  
    93  	return s.hypervisor.addDevice(d, vhostuserDev)
    94  }
    95  
    96  // Detach for vhostuser endpoint
    97  func (endpoint *VhostUserEndpoint) Detach(netNsCreated bool, netNsPath string) error {
    98  	return nil
    99  }
   100  
   101  // HotAttach for vhostuser endpoint not supported yet
   102  func (endpoint *VhostUserEndpoint) HotAttach(h hypervisor) error {
   103  	return fmt.Errorf("VhostUserEndpoint does not support Hot attach")
   104  }
   105  
   106  // HotDetach for vhostuser endpoint not supported yet
   107  func (endpoint *VhostUserEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
   108  	return fmt.Errorf("VhostUserEndpoint does not support Hot detach")
   109  }
   110  
   111  // Create a vhostuser endpoint
   112  func createVhostUserEndpoint(netInfo NetworkInfo, socket string) (*VhostUserEndpoint, error) {
   113  
   114  	vhostUserEndpoint := &VhostUserEndpoint{
   115  		SocketPath:   socket,
   116  		HardAddr:     netInfo.Iface.HardwareAddr.String(),
   117  		IfaceName:    netInfo.Iface.Name,
   118  		EndpointType: VhostUserEndpointType,
   119  	}
   120  	return vhostUserEndpoint, nil
   121  }
   122  
   123  // findVhostUserNetSocketPath checks if an interface is a dummy placeholder
   124  // for a vhost-user socket, and if it is it returns the path to the socket
   125  func findVhostUserNetSocketPath(netInfo NetworkInfo) (string, error) {
   126  	if netInfo.Iface.Name == "lo" {
   127  		return "", nil
   128  	}
   129  
   130  	// check for socket file existence at known location.
   131  	for _, addr := range netInfo.Addrs {
   132  		socketPath := fmt.Sprintf(hostSocketSearchPath, addr.IPNet.IP)
   133  		if _, err := os.Stat(socketPath); err == nil {
   134  			return socketPath, nil
   135  		}
   136  	}
   137  
   138  	return "", nil
   139  }
   140  
   141  // vhostUserSocketPath returns the path of the socket discovered.  This discovery
   142  // will vary depending on the type of vhost-user socket.
   143  //  Today only VhostUserNetDevice is supported.
   144  func vhostUserSocketPath(info interface{}) (string, error) {
   145  
   146  	switch v := info.(type) {
   147  	case NetworkInfo:
   148  		return findVhostUserNetSocketPath(v)
   149  	default:
   150  		return "", nil
   151  	}
   152  
   153  }
   154  
   155  func (endpoint *VhostUserEndpoint) save() persistapi.NetworkEndpoint {
   156  	return persistapi.NetworkEndpoint{
   157  		Type: string(endpoint.Type()),
   158  		VhostUser: &persistapi.VhostUserEndpoint{
   159  			IfaceName: endpoint.IfaceName,
   160  			PCIPath:   endpoint.PCIPath,
   161  		},
   162  	}
   163  }
   164  
   165  func (endpoint *VhostUserEndpoint) load(s persistapi.NetworkEndpoint) {
   166  	endpoint.EndpointType = VhostUserEndpointType
   167  
   168  	if s.VhostUser != nil {
   169  		endpoint.IfaceName = s.VhostUser.IfaceName
   170  		endpoint.PCIPath = s.VhostUser.PCIPath
   171  	}
   172  }