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

     1  // Copyright (c) 2017 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package virtcontainers
     7  
     8  import (
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  	"strconv"
    16  	"strings"
    17  	"sync"
    18  	"syscall"
    19  	"time"
    20  
    21  	units "github.com/docker/go-units"
    22  	"github.com/gogo/protobuf/proto"
    23  	aTypes "github.com/kata-containers/agent/pkg/types"
    24  	kataclient "github.com/kata-containers/agent/protocols/client"
    25  	"github.com/kata-containers/agent/protocols/grpc"
    26  	"github.com/kata-containers/runtime/virtcontainers/device/api"
    27  	"github.com/kata-containers/runtime/virtcontainers/device/config"
    28  	persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
    29  	vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
    30  	vccgroups "github.com/kata-containers/runtime/virtcontainers/pkg/cgroups"
    31  	ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
    32  	"github.com/kata-containers/runtime/virtcontainers/pkg/rootless"
    33  	vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
    34  	"github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
    35  	"github.com/kata-containers/runtime/virtcontainers/store"
    36  	"github.com/kata-containers/runtime/virtcontainers/types"
    37  	"github.com/kata-containers/runtime/virtcontainers/utils"
    38  	"github.com/opencontainers/runtime-spec/specs-go"
    39  	opentracing "github.com/opentracing/opentracing-go"
    40  	"github.com/sirupsen/logrus"
    41  	"github.com/vishvananda/netlink"
    42  	"golang.org/x/net/context"
    43  	"golang.org/x/sys/unix"
    44  	golangGrpc "google.golang.org/grpc"
    45  	"google.golang.org/grpc/codes"
    46  	grpcStatus "google.golang.org/grpc/status"
    47  )
    48  
    49  const (
    50  	// KataEphemeralDevType creates a tmpfs backed volume for sharing files between containers.
    51  	KataEphemeralDevType = "ephemeral"
    52  
    53  	// KataLocalDevType creates a local directory inside the VM for sharing files between
    54  	// containers.
    55  	KataLocalDevType = "local"
    56  
    57  	// path to vfio devices
    58  	vfioPath = "/dev/vfio/"
    59  
    60  	agentPidEnv = "KATA_AGENT_PIDNS"
    61  )
    62  
    63  var (
    64  	checkRequestTimeout         = 30 * time.Second
    65  	defaultRequestTimeout       = 60 * time.Second
    66  	errorMissingProxy           = errors.New("Missing proxy pointer")
    67  	errorMissingOCISpec         = errors.New("Missing OCI specification")
    68  	defaultKataHostSharedDir    = "/run/kata-containers/shared/sandboxes/"
    69  	defaultKataGuestSharedDir   = "/run/kata-containers/shared/containers/"
    70  	mountGuestTag               = "kataShared"
    71  	defaultKataGuestSandboxDir  = "/run/kata-containers/sandbox/"
    72  	type9pFs                    = "9p"
    73  	typeVirtioFS                = "virtiofs"
    74  	typeVirtioFSNoCache         = "none"
    75  	kata9pDevType               = "9p"
    76  	kataMmioBlkDevType          = "mmioblk"
    77  	kataBlkDevType              = "blk"
    78  	kataBlkCCWDevType           = "blk-ccw"
    79  	kataSCSIDevType             = "scsi"
    80  	kataNvdimmDevType           = "nvdimm"
    81  	kataVirtioFSDevType         = "virtio-fs"
    82  	sharedDir9pOptions          = []string{"trans=virtio,version=9p2000.L,cache=mmap", "nodev"}
    83  	sharedDirVirtioFSOptions    = []string{}
    84  	sharedDirVirtioFSDaxOptions = "dax"
    85  	shmDir                      = "shm"
    86  	kataEphemeralDevType        = "ephemeral"
    87  	defaultEphemeralPath        = filepath.Join(defaultKataGuestSandboxDir, kataEphemeralDevType)
    88  	grpcMaxDataSize             = int64(1024 * 1024)
    89  	localDirOptions             = []string{"mode=0777"}
    90  	maxHostnameLen              = 64
    91  	GuestDNSFile                = "/etc/resolv.conf"
    92  )
    93  
    94  const (
    95  	agentTraceModeDynamic  = "dynamic"
    96  	agentTraceModeStatic   = "static"
    97  	agentTraceTypeIsolated = "isolated"
    98  	agentTraceTypeCollated = "collated"
    99  
   100  	defaultAgentTraceMode = agentTraceModeDynamic
   101  	defaultAgentTraceType = agentTraceTypeIsolated
   102  )
   103  
   104  const (
   105  	grpcCheckRequest             = "grpc.CheckRequest"
   106  	grpcExecProcessRequest       = "grpc.ExecProcessRequest"
   107  	grpcCreateSandboxRequest     = "grpc.CreateSandboxRequest"
   108  	grpcDestroySandboxRequest    = "grpc.DestroySandboxRequest"
   109  	grpcCreateContainerRequest   = "grpc.CreateContainerRequest"
   110  	grpcStartContainerRequest    = "grpc.StartContainerRequest"
   111  	grpcRemoveContainerRequest   = "grpc.RemoveContainerRequest"
   112  	grpcSignalProcessRequest     = "grpc.SignalProcessRequest"
   113  	grpcUpdateRoutesRequest      = "grpc.UpdateRoutesRequest"
   114  	grpcUpdateInterfaceRequest   = "grpc.UpdateInterfaceRequest"
   115  	grpcListInterfacesRequest    = "grpc.ListInterfacesRequest"
   116  	grpcListRoutesRequest        = "grpc.ListRoutesRequest"
   117  	grpcAddARPNeighborsRequest   = "grpc.AddARPNeighborsRequest"
   118  	grpcOnlineCPUMemRequest      = "grpc.OnlineCPUMemRequest"
   119  	grpcListProcessesRequest     = "grpc.ListProcessesRequest"
   120  	grpcUpdateContainerRequest   = "grpc.UpdateContainerRequest"
   121  	grpcWaitProcessRequest       = "grpc.WaitProcessRequest"
   122  	grpcTtyWinResizeRequest      = "grpc.TtyWinResizeRequest"
   123  	grpcWriteStreamRequest       = "grpc.WriteStreamRequest"
   124  	grpcCloseStdinRequest        = "grpc.CloseStdinRequest"
   125  	grpcStatsContainerRequest    = "grpc.StatsContainerRequest"
   126  	grpcPauseContainerRequest    = "grpc.PauseContainerRequest"
   127  	grpcResumeContainerRequest   = "grpc.ResumeContainerRequest"
   128  	grpcReseedRandomDevRequest   = "grpc.ReseedRandomDevRequest"
   129  	grpcGuestDetailsRequest      = "grpc.GuestDetailsRequest"
   130  	grpcMemHotplugByProbeRequest = "grpc.MemHotplugByProbeRequest"
   131  	grpcCopyFileRequest          = "grpc.CopyFileRequest"
   132  	grpcSetGuestDateTimeRequest  = "grpc.SetGuestDateTimeRequest"
   133  	grpcStartTracingRequest      = "grpc.StartTracingRequest"
   134  	grpcStopTracingRequest       = "grpc.StopTracingRequest"
   135  	grpcGetOOMEventRequest       = "grpc.GetOOMEventRequest"
   136  )
   137  
   138  // The function is declared this way for mocking in unit tests
   139  var kataHostSharedDir = func() string {
   140  	if rootless.IsRootless() {
   141  		// filepath.Join removes trailing slashes, but it is necessary for mounting
   142  		return filepath.Join(rootless.GetRootlessDir(), defaultKataHostSharedDir) + "/"
   143  	}
   144  	return defaultKataHostSharedDir
   145  }
   146  
   147  func getPagesizeFromOpt(fsOpts []string) string {
   148  	//example options array: "rw", "relatime", "seclabel", "pagesize=2M"
   149  
   150  	for _, opt := range fsOpts {
   151  		if strings.HasPrefix(opt, "pagesize=") {
   152  			return strings.TrimPrefix(opt, "pagesize=")
   153  		}
   154  	}
   155  	return ""
   156  }
   157  
   158  // Shared path handling:
   159  // 1. create two directories for each sandbox:
   160  // -. /run/kata-containers/shared/sandboxes/$sbx_id/mounts/, a directory to hold all host/guest shared mounts
   161  // -. /run/kata-containers/shared/sandboxes/$sbx_id/shared/, a host/guest shared directory (9pfs/virtiofs source dir)
   162  //
   163  // 2. /run/kata-containers/shared/sandboxes/$sbx_id/mounts/ is bind mounted readonly to /run/kata-containers/shared/sandboxes/$sbx_id/shared/, so guest cannot modify it
   164  //
   165  // 3. host-guest shared files/directories are mounted one-level under /run/kata-containers/shared/sandboxes/$sbx_id/mounts/ and thus present to guest at one level under /run/kata-containers/shared/sandboxes/$sbx_id/shared/
   166  func getSharePath(id string) string {
   167  	return filepath.Join(kataHostSharedDir(), id, "shared")
   168  }
   169  
   170  func getMountPath(id string) string {
   171  	return filepath.Join(kataHostSharedDir(), id, "mounts")
   172  }
   173  
   174  func getSandboxPath(id string) string {
   175  	return filepath.Join(kataHostSharedDir(), id)
   176  }
   177  
   178  // The function is declared this way for mocking in unit tests
   179  var kataGuestSharedDir = func() string {
   180  	if rootless.IsRootless() {
   181  		// filepath.Join removes trailing slashes, but it is necessary for mounting
   182  		return filepath.Join(rootless.GetRootlessDir(), defaultKataGuestSharedDir) + "/"
   183  	}
   184  	return defaultKataGuestSharedDir
   185  }
   186  
   187  // The function is declared this way for mocking in unit tests
   188  var kataGuestSandboxDir = func() string {
   189  	if rootless.IsRootless() {
   190  		// filepath.Join removes trailing slashes, but it is necessary for mounting
   191  		return filepath.Join(rootless.GetRootlessDir(), defaultKataGuestSandboxDir) + "/"
   192  	}
   193  	return defaultKataGuestSandboxDir
   194  }
   195  
   196  var kataGuestSandboxStorageDir = func() string {
   197  	return filepath.Join(defaultKataGuestSandboxDir, "storage")
   198  }
   199  
   200  func ephemeralPath() string {
   201  	if rootless.IsRootless() {
   202  		return filepath.Join(kataGuestSandboxDir(), kataEphemeralDevType)
   203  	}
   204  	return defaultEphemeralPath
   205  }
   206  
   207  // KataAgentConfig is a structure storing information needed
   208  // to reach the Kata Containers agent.
   209  type KataAgentConfig struct {
   210  	LongLiveConn      bool
   211  	UseVSock          bool
   212  	Debug             bool
   213  	Trace             bool
   214  	ContainerPipeSize uint32
   215  	TraceMode         string
   216  	TraceType         string
   217  	KernelModules     []string
   218  }
   219  
   220  // KataAgentState is the structure describing the data stored from this
   221  // agent implementation.
   222  type KataAgentState struct {
   223  	ProxyPid int
   224  	URL      string
   225  }
   226  
   227  type kataAgent struct {
   228  	shim  shim
   229  	proxy proxy
   230  
   231  	// lock protects the client pointer
   232  	sync.Mutex
   233  	client *kataclient.AgentClient
   234  
   235  	reqHandlers    map[string]reqFunc
   236  	state          KataAgentState
   237  	keepConn       bool
   238  	proxyBuiltIn   bool
   239  	dynamicTracing bool
   240  	dead           bool
   241  	kmodules       []string
   242  
   243  	vmSocket interface{}
   244  	ctx      context.Context
   245  }
   246  
   247  func (k *kataAgent) trace(name string) (opentracing.Span, context.Context) {
   248  	if k.ctx == nil {
   249  		k.Logger().WithField("type", "bug").Error("trace called before context set")
   250  		k.ctx = context.Background()
   251  	}
   252  
   253  	span, ctx := opentracing.StartSpanFromContext(k.ctx, name)
   254  
   255  	span.SetTag("subsystem", "agent")
   256  	span.SetTag("type", "kata")
   257  
   258  	return span, ctx
   259  }
   260  
   261  func (k *kataAgent) Logger() *logrus.Entry {
   262  	return virtLog.WithField("subsystem", "kata_agent")
   263  }
   264  
   265  func (k *kataAgent) longLiveConn() bool {
   266  	return k.keepConn
   267  }
   268  
   269  // KataAgentSetDefaultTraceConfigOptions validates agent trace options and
   270  // sets defaults.
   271  func KataAgentSetDefaultTraceConfigOptions(config *KataAgentConfig) error {
   272  	if !config.Trace {
   273  		return nil
   274  	}
   275  
   276  	switch config.TraceMode {
   277  	case agentTraceModeDynamic:
   278  	case agentTraceModeStatic:
   279  	case "":
   280  		config.TraceMode = defaultAgentTraceMode
   281  	default:
   282  		return fmt.Errorf("invalid kata agent trace mode: %q (need %q or %q)", config.TraceMode, agentTraceModeDynamic, agentTraceModeStatic)
   283  	}
   284  
   285  	switch config.TraceType {
   286  	case agentTraceTypeIsolated:
   287  	case agentTraceTypeCollated:
   288  	case "":
   289  		config.TraceType = defaultAgentTraceType
   290  	default:
   291  		return fmt.Errorf("invalid kata agent trace type: %q (need %q or %q)", config.TraceType, agentTraceTypeIsolated, agentTraceTypeCollated)
   292  	}
   293  
   294  	return nil
   295  }
   296  
   297  // KataAgentKernelParams returns a list of Kata Agent specific kernel
   298  // parameters.
   299  func KataAgentKernelParams(config KataAgentConfig) []Param {
   300  	var params []Param
   301  
   302  	if config.Debug {
   303  		params = append(params, Param{Key: "agent.log", Value: "debug"})
   304  	}
   305  
   306  	if config.Trace && config.TraceMode == agentTraceModeStatic {
   307  		params = append(params, Param{Key: "agent.trace", Value: config.TraceType})
   308  	}
   309  
   310  	if config.ContainerPipeSize > 0 {
   311  		containerPipeSize := strconv.FormatUint(uint64(config.ContainerPipeSize), 10)
   312  		params = append(params, Param{Key: vcAnnotations.ContainerPipeSizeKernelParam, Value: containerPipeSize})
   313  	}
   314  
   315  	return params
   316  }
   317  
   318  func (k *kataAgent) handleTraceSettings(config KataAgentConfig) bool {
   319  	if !config.Trace {
   320  		return false
   321  	}
   322  
   323  	disableVMShutdown := false
   324  
   325  	switch config.TraceMode {
   326  	case agentTraceModeStatic:
   327  		disableVMShutdown = true
   328  	case agentTraceModeDynamic:
   329  		k.dynamicTracing = true
   330  	}
   331  
   332  	return disableVMShutdown
   333  }
   334  
   335  func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface{}) (disableVMShutdown bool, err error) {
   336  	// save
   337  	k.ctx = sandbox.ctx
   338  
   339  	span, _ := k.trace("init")
   340  	defer span.Finish()
   341  
   342  	switch c := config.(type) {
   343  	case KataAgentConfig:
   344  		disableVMShutdown = k.handleTraceSettings(c)
   345  		k.keepConn = c.LongLiveConn
   346  		k.kmodules = c.KernelModules
   347  	default:
   348  		return false, vcTypes.ErrInvalidConfigType
   349  	}
   350  
   351  	k.proxy, err = newProxy(sandbox.config.ProxyType)
   352  	if err != nil {
   353  		return false, err
   354  	}
   355  
   356  	k.shim, err = newShim(sandbox.config.ShimType)
   357  	if err != nil {
   358  		return false, err
   359  	}
   360  
   361  	k.proxyBuiltIn = isProxyBuiltIn(sandbox.config.ProxyType)
   362  
   363  	// Fetch agent runtime info.
   364  	if useOldStore(sandbox.ctx) {
   365  		if err := sandbox.store.Load(store.Agent, &k.state); err != nil {
   366  			k.Logger().Debug("Could not retrieve anything from storage")
   367  		}
   368  	}
   369  	return disableVMShutdown, nil
   370  }
   371  
   372  func (k *kataAgent) agentURL() (string, error) {
   373  	switch s := k.vmSocket.(type) {
   374  	case types.Socket:
   375  		return s.HostPath, nil
   376  	case types.VSock:
   377  		return s.String(), nil
   378  	case types.HybridVSock:
   379  		return s.String(), nil
   380  	default:
   381  		return "", fmt.Errorf("Invalid socket type")
   382  	}
   383  }
   384  
   385  func (k *kataAgent) capabilities() types.Capabilities {
   386  	var caps types.Capabilities
   387  
   388  	// add all capabilities supported by agent
   389  	caps.SetBlockDeviceSupport()
   390  
   391  	return caps
   392  }
   393  
   394  func (k *kataAgent) internalConfigure(h hypervisor, id string, builtin bool, config interface{}) error {
   395  	var err error
   396  	if config != nil {
   397  		switch c := config.(type) {
   398  		case KataAgentConfig:
   399  			if k.vmSocket, err = h.generateSocket(id, c.UseVSock); err != nil {
   400  				return err
   401  			}
   402  			k.keepConn = c.LongLiveConn
   403  		default:
   404  			return vcTypes.ErrInvalidConfigType
   405  		}
   406  	}
   407  
   408  	if builtin {
   409  		k.proxyBuiltIn = true
   410  	}
   411  
   412  	return nil
   413  }
   414  
   415  func (k *kataAgent) configure(h hypervisor, id, sharePath string, builtin bool, config interface{}) error {
   416  	err := k.internalConfigure(h, id, builtin, config)
   417  	if err != nil {
   418  		return err
   419  	}
   420  
   421  	switch s := k.vmSocket.(type) {
   422  	case types.Socket:
   423  		err = h.addDevice(s, serialPortDev)
   424  		if err != nil {
   425  			return err
   426  		}
   427  	case types.VSock:
   428  		if err = h.addDevice(s, vSockPCIDev); err != nil {
   429  			return err
   430  		}
   431  	case types.HybridVSock:
   432  		err = h.addDevice(s, hybridVirtioVsockDev)
   433  		if err != nil {
   434  			return err
   435  		}
   436  	default:
   437  		return vcTypes.ErrInvalidConfigType
   438  	}
   439  
   440  	// Neither create shared directory nor add 9p device if hypervisor
   441  	// doesn't support filesystem sharing.
   442  	caps := h.capabilities()
   443  	if !caps.IsFsSharingSupported() {
   444  		return nil
   445  	}
   446  
   447  	// Create shared directory and add the shared volume if filesystem sharing is supported.
   448  	// This volume contains all bind mounted container bundles.
   449  	sharedVolume := types.Volume{
   450  		MountTag: mountGuestTag,
   451  		HostPath: sharePath,
   452  	}
   453  
   454  	if err = os.MkdirAll(sharedVolume.HostPath, DirMode); err != nil {
   455  		return err
   456  	}
   457  
   458  	return h.addDevice(sharedVolume, fsDev)
   459  }
   460  
   461  func (k *kataAgent) configureFromGrpc(h hypervisor, id string, builtin bool, config interface{}) error {
   462  	return k.internalConfigure(h, id, builtin, config)
   463  }
   464  
   465  func (k *kataAgent) setupSharedPath(sandbox *Sandbox) error {
   466  	// create shared path structure
   467  	sharePath := getSharePath(sandbox.id)
   468  	mountPath := getMountPath(sandbox.id)
   469  	if err := os.MkdirAll(sharePath, DirMode); err != nil {
   470  		return err
   471  	}
   472  	if err := os.MkdirAll(mountPath, DirMode); err != nil {
   473  		return err
   474  	}
   475  
   476  	// slave mount so that future mountpoints under mountPath are shown in sharePath as well
   477  	if err := bindMount(context.Background(), mountPath, sharePath, true, "slave"); err != nil {
   478  		return err
   479  	}
   480  
   481  	return nil
   482  }
   483  
   484  func (k *kataAgent) createSandbox(sandbox *Sandbox) error {
   485  	span, _ := k.trace("createSandbox")
   486  	defer span.Finish()
   487  
   488  	if err := k.setupSharedPath(sandbox); err != nil {
   489  		return err
   490  	}
   491  	return k.configure(sandbox.hypervisor, sandbox.id, getSharePath(sandbox.id), k.proxyBuiltIn, sandbox.config.AgentConfig)
   492  }
   493  
   494  func cmdToKataProcess(cmd types.Cmd) (process *grpc.Process, err error) {
   495  	var i uint64
   496  	var extraGids []uint32
   497  
   498  	// Number of bits used to store user+group values in
   499  	// the gRPC "User" type.
   500  	const grpcUserBits = 32
   501  
   502  	// User can contain only the "uid" or it can contain "uid:gid".
   503  	parsedUser := strings.Split(cmd.User, ":")
   504  	if len(parsedUser) > 2 {
   505  		return nil, fmt.Errorf("cmd.User %q format is wrong", cmd.User)
   506  	}
   507  
   508  	i, err = strconv.ParseUint(parsedUser[0], 10, grpcUserBits)
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  
   513  	uid := uint32(i)
   514  
   515  	var gid uint32
   516  	if len(parsedUser) > 1 {
   517  		i, err = strconv.ParseUint(parsedUser[1], 10, grpcUserBits)
   518  		if err != nil {
   519  			return nil, err
   520  		}
   521  
   522  		gid = uint32(i)
   523  	}
   524  
   525  	if cmd.PrimaryGroup != "" {
   526  		i, err = strconv.ParseUint(cmd.PrimaryGroup, 10, grpcUserBits)
   527  		if err != nil {
   528  			return nil, err
   529  		}
   530  
   531  		gid = uint32(i)
   532  	}
   533  
   534  	for _, g := range cmd.SupplementaryGroups {
   535  		var extraGid uint64
   536  
   537  		extraGid, err = strconv.ParseUint(g, 10, grpcUserBits)
   538  		if err != nil {
   539  			return nil, err
   540  		}
   541  
   542  		extraGids = append(extraGids, uint32(extraGid))
   543  	}
   544  
   545  	process = &grpc.Process{
   546  		Terminal: cmd.Interactive,
   547  		User: grpc.User{
   548  			UID:            uid,
   549  			GID:            gid,
   550  			AdditionalGids: extraGids,
   551  		},
   552  		Args: cmd.Args,
   553  		Env:  cmdEnvsToStringSlice(cmd.Envs),
   554  		Cwd:  cmd.WorkDir,
   555  	}
   556  
   557  	return process, nil
   558  }
   559  
   560  func cmdEnvsToStringSlice(ev []types.EnvVar) []string {
   561  	var env []string
   562  
   563  	for _, e := range ev {
   564  		pair := []string{e.Var, e.Value}
   565  		env = append(env, strings.Join(pair, "="))
   566  	}
   567  
   568  	return env
   569  }
   570  
   571  func (k *kataAgent) exec(sandbox *Sandbox, c Container, cmd types.Cmd) (*Process, error) {
   572  	span, _ := k.trace("exec")
   573  	defer span.Finish()
   574  
   575  	var kataProcess *grpc.Process
   576  
   577  	kataProcess, err := cmdToKataProcess(cmd)
   578  	if err != nil {
   579  		return nil, err
   580  	}
   581  
   582  	req := &grpc.ExecProcessRequest{
   583  		ContainerId: c.id,
   584  		ExecId:      uuid.Generate().String(),
   585  		Process:     kataProcess,
   586  	}
   587  
   588  	if _, err := k.sendReq(req); err != nil {
   589  		return nil, err
   590  	}
   591  
   592  	enterNSList := []ns.Namespace{
   593  		{
   594  			PID:  c.process.Pid,
   595  			Type: ns.NSTypeNet,
   596  		},
   597  		{
   598  			PID:  c.process.Pid,
   599  			Type: ns.NSTypePID,
   600  		},
   601  	}
   602  
   603  	return prepareAndStartShim(sandbox, k.shim, c.id, req.ExecId,
   604  		k.state.URL, "", cmd, []ns.NSType{}, enterNSList)
   605  }
   606  
   607  func (k *kataAgent) updateInterface(ifc *vcTypes.Interface) (*vcTypes.Interface, error) {
   608  	// send update interface request
   609  	ifcReq := &grpc.UpdateInterfaceRequest{
   610  		Interface: k.convertToKataAgentInterface(ifc),
   611  	}
   612  	resultingInterface, err := k.sendReq(ifcReq)
   613  	if err != nil {
   614  		k.Logger().WithFields(logrus.Fields{
   615  			"interface-requested": fmt.Sprintf("%+v", ifc),
   616  			"resulting-interface": fmt.Sprintf("%+v", resultingInterface),
   617  		}).WithError(err).Error("update interface request failed")
   618  	}
   619  	if resultInterface, ok := resultingInterface.(*vcTypes.Interface); ok {
   620  		return resultInterface, err
   621  	}
   622  	return nil, err
   623  }
   624  
   625  func (k *kataAgent) updateInterfaces(interfaces []*vcTypes.Interface) error {
   626  	for _, ifc := range interfaces {
   627  		if _, err := k.updateInterface(ifc); err != nil {
   628  			return err
   629  		}
   630  	}
   631  	return nil
   632  }
   633  
   634  func (k *kataAgent) updateRoutes(routes []*vcTypes.Route) ([]*vcTypes.Route, error) {
   635  	if routes != nil {
   636  		routesReq := &grpc.UpdateRoutesRequest{
   637  			Routes: &grpc.Routes{
   638  				Routes: k.convertToKataAgentRoutes(routes),
   639  			},
   640  		}
   641  		resultingRoutes, err := k.sendReq(routesReq)
   642  		if err != nil {
   643  			k.Logger().WithFields(logrus.Fields{
   644  				"routes-requested": fmt.Sprintf("%+v", routes),
   645  				"resulting-routes": fmt.Sprintf("%+v", resultingRoutes),
   646  			}).WithError(err).Error("update routes request failed")
   647  		}
   648  		resultRoutes, ok := resultingRoutes.(*grpc.Routes)
   649  		if ok && resultRoutes != nil {
   650  			return k.convertToRoutes(resultRoutes.Routes), err
   651  		}
   652  		return nil, err
   653  	}
   654  	return nil, nil
   655  }
   656  
   657  func (k *kataAgent) addARPNeighbors(neighs []*vcTypes.ARPNeighbor) error {
   658  	if neighs != nil {
   659  		neighsReq := &grpc.AddARPNeighborsRequest{
   660  			Neighbors: &grpc.ARPNeighbors{
   661  				ARPNeighbors: k.convertToKataAgentNeighbors(neighs),
   662  			},
   663  		}
   664  		_, err := k.sendReq(neighsReq)
   665  		if err != nil {
   666  			if grpcStatus.Convert(err).Code() == codes.Unimplemented {
   667  				k.Logger().WithFields(logrus.Fields{
   668  					"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
   669  				}).Warn("add ARP neighbors request failed due to old agent, please upgrade Kata Containers image version")
   670  				return nil
   671  			}
   672  			k.Logger().WithFields(logrus.Fields{
   673  				"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
   674  			}).WithError(err).Error("add ARP neighbors request failed")
   675  		}
   676  		return err
   677  	}
   678  	return nil
   679  }
   680  
   681  func (k *kataAgent) listInterfaces() ([]*vcTypes.Interface, error) {
   682  	req := &grpc.ListInterfacesRequest{}
   683  	resultingInterfaces, err := k.sendReq(req)
   684  	if err != nil {
   685  		return nil, err
   686  	}
   687  	resultInterfaces, ok := resultingInterfaces.(*grpc.Interfaces)
   688  	if !ok {
   689  		return nil, fmt.Errorf("Unexpected type %T for interfaces", resultingInterfaces)
   690  	}
   691  	return k.convertToInterfaces(resultInterfaces.Interfaces)
   692  }
   693  
   694  func (k *kataAgent) listRoutes() ([]*vcTypes.Route, error) {
   695  	req := &grpc.ListRoutesRequest{}
   696  	resultingRoutes, err := k.sendReq(req)
   697  	if err != nil {
   698  		return nil, err
   699  	}
   700  	resultRoutes, ok := resultingRoutes.(*grpc.Routes)
   701  	if !ok {
   702  		return nil, fmt.Errorf("Unexpected type %T for routes", resultingRoutes)
   703  	}
   704  	return k.convertToRoutes(resultRoutes.Routes), nil
   705  }
   706  
   707  func (k *kataAgent) startProxy(sandbox *Sandbox) error {
   708  	span, _ := k.trace("startProxy")
   709  	defer span.Finish()
   710  
   711  	var err error
   712  	var agentURL string
   713  
   714  	if k.proxy == nil {
   715  		return errorMissingProxy
   716  	}
   717  
   718  	if k.proxy.consoleWatched() {
   719  		return nil
   720  	}
   721  
   722  	if k.state.URL != "" {
   723  		// For keepConn case, when k.state.URL isn't nil, it means shimv2 had disconnected from
   724  		// sandbox and try to relaunch sandbox again. Here it needs to start proxy again to watch
   725  		// the hypervisor console.
   726  		if k.keepConn {
   727  			agentURL = k.state.URL
   728  		} else {
   729  			k.Logger().WithFields(logrus.Fields{
   730  				"sandbox":   sandbox.id,
   731  				"proxy-pid": k.state.ProxyPid,
   732  				"proxy-url": k.state.URL,
   733  			}).Infof("proxy already started")
   734  			return nil
   735  		}
   736  	} else {
   737  		// Get agent socket path to provide it to the proxy.
   738  		agentURL, err = k.agentURL()
   739  		if err != nil {
   740  			return err
   741  		}
   742  	}
   743  
   744  	consoleURL, err := sandbox.hypervisor.getSandboxConsole(sandbox.id)
   745  	if err != nil {
   746  		return err
   747  	}
   748  
   749  	proxyParams := proxyParams{
   750  		id:         sandbox.id,
   751  		hid:        getHypervisorPid(sandbox.hypervisor),
   752  		path:       sandbox.config.ProxyConfig.Path,
   753  		agentURL:   agentURL,
   754  		consoleURL: consoleURL,
   755  		logger:     k.Logger().WithField("sandbox", sandbox.id),
   756  		// Disable debug so proxy doesn't read console if we want to
   757  		// debug the agent console ourselves.
   758  		debug: sandbox.config.ProxyConfig.Debug &&
   759  			!k.hasAgentDebugConsole(sandbox),
   760  	}
   761  
   762  	// Start the proxy here
   763  	pid, uri, err := k.proxy.start(proxyParams)
   764  	if err != nil {
   765  		return err
   766  	}
   767  
   768  	// If error occurs after kata-proxy process start,
   769  	// then rollback to kill kata-proxy process
   770  	defer func() {
   771  		if err != nil {
   772  			k.proxy.stop(pid)
   773  		}
   774  	}()
   775  
   776  	// Fill agent state with proxy information, and store them.
   777  	if err = k.setProxy(sandbox, k.proxy, pid, uri); err != nil {
   778  		return err
   779  	}
   780  
   781  	k.Logger().WithFields(logrus.Fields{
   782  		"sandbox":   sandbox.id,
   783  		"proxy-pid": pid,
   784  		"proxy-url": uri,
   785  	}).Info("proxy started")
   786  
   787  	return nil
   788  }
   789  
   790  func (k *kataAgent) getAgentURL() (string, error) {
   791  	return k.agentURL()
   792  }
   793  
   794  func (k *kataAgent) reuseAgent(agent agent) error {
   795  	a, ok := agent.(*kataAgent)
   796  	if !ok {
   797  		return fmt.Errorf("Bug: get a wrong type of agent")
   798  	}
   799  
   800  	k.installReqFunc(a.client)
   801  	k.client = a.client
   802  	return nil
   803  }
   804  
   805  func (k *kataAgent) setProxy(sandbox *Sandbox, proxy proxy, pid int, url string) error {
   806  	if url == "" {
   807  		var err error
   808  		if url, err = k.agentURL(); err != nil {
   809  			return err
   810  		}
   811  	}
   812  
   813  	// Are we setting the same proxy again?
   814  	if k.proxy != nil && k.state.URL != "" && k.state.URL != url {
   815  		k.proxy.stop(k.state.ProxyPid)
   816  	}
   817  
   818  	k.proxy = proxy
   819  	k.state.ProxyPid = pid
   820  	k.state.URL = url
   821  	return nil
   822  }
   823  
   824  func (k *kataAgent) setProxyFromGrpc(proxy proxy, pid int, url string) {
   825  	k.proxy = proxy
   826  	k.state.ProxyPid = pid
   827  	k.state.URL = url
   828  }
   829  
   830  func (k *kataAgent) getDNS(sandbox *Sandbox) ([]string, error) {
   831  	ociSpec := sandbox.GetPatchedOCISpec()
   832  	if ociSpec == nil {
   833  		k.Logger().Debug("Sandbox OCI spec not found. Sandbox DNS will not be set.")
   834  		return nil, nil
   835  	}
   836  
   837  	ociMounts := ociSpec.Mounts
   838  
   839  	for _, m := range ociMounts {
   840  		if m.Destination == GuestDNSFile {
   841  			content, err := ioutil.ReadFile(m.Source)
   842  			if err != nil {
   843  				return nil, fmt.Errorf("Could not read file %s: %s", m.Source, err)
   844  			}
   845  			dns := strings.Split(string(content), "\n")
   846  			return dns, nil
   847  
   848  		}
   849  	}
   850  	k.Logger().Debug("DNS file not present in ociMounts. Sandbox DNS will not be set.")
   851  	return nil, nil
   852  }
   853  
   854  func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
   855  	span, _ := k.trace("startSandbox")
   856  	defer span.Finish()
   857  
   858  	err := k.startProxy(sandbox)
   859  	if err != nil {
   860  		return err
   861  	}
   862  
   863  	defer func() {
   864  		if err != nil {
   865  			k.proxy.stop(k.state.ProxyPid)
   866  		}
   867  	}()
   868  	hostname := sandbox.config.Hostname
   869  	if len(hostname) > maxHostnameLen {
   870  		hostname = hostname[:maxHostnameLen]
   871  	}
   872  
   873  	dns, err := k.getDNS(sandbox)
   874  	if err != nil {
   875  		return err
   876  	}
   877  
   878  	// check grpc server is serving
   879  	if err = k.check(); err != nil {
   880  		return err
   881  	}
   882  
   883  	//
   884  	// Setup network interfaces and routes
   885  	//
   886  	interfaces, routes, neighs, err := generateVCNetworkStructures(sandbox.networkNS)
   887  	if err != nil {
   888  		return err
   889  	}
   890  	if err = k.updateInterfaces(interfaces); err != nil {
   891  		return err
   892  	}
   893  	if _, err = k.updateRoutes(routes); err != nil {
   894  		return err
   895  	}
   896  	if err = k.addARPNeighbors(neighs); err != nil {
   897  		return err
   898  	}
   899  
   900  	storages := setupStorages(sandbox)
   901  
   902  	kmodules := setupKernelModules(k.kmodules)
   903  
   904  	req := &grpc.CreateSandboxRequest{
   905  		Hostname:      hostname,
   906  		Dns:           dns,
   907  		Storages:      storages,
   908  		SandboxPidns:  sandbox.sharePidNs,
   909  		SandboxId:     sandbox.id,
   910  		GuestHookPath: sandbox.config.HypervisorConfig.GuestHookPath,
   911  		KernelModules: kmodules,
   912  	}
   913  
   914  	_, err = k.sendReq(req)
   915  	if err != nil {
   916  		return err
   917  	}
   918  
   919  	if k.dynamicTracing {
   920  		_, err = k.sendReq(&grpc.StartTracingRequest{})
   921  		if err != nil {
   922  			return err
   923  		}
   924  	}
   925  
   926  	return nil
   927  }
   928  
   929  func setupKernelModules(kmodules []string) []*grpc.KernelModule {
   930  	modules := []*grpc.KernelModule{}
   931  
   932  	for _, m := range kmodules {
   933  		l := strings.Fields(strings.TrimSpace(m))
   934  		if len(l) == 0 {
   935  			continue
   936  		}
   937  
   938  		module := &grpc.KernelModule{Name: l[0]}
   939  		modules = append(modules, module)
   940  		if len(l) == 1 {
   941  			continue
   942  		}
   943  
   944  		module.Parameters = append(module.Parameters, l[1:]...)
   945  	}
   946  
   947  	return modules
   948  }
   949  
   950  func setupStorages(sandbox *Sandbox) []*grpc.Storage {
   951  	storages := []*grpc.Storage{}
   952  	caps := sandbox.hypervisor.capabilities()
   953  
   954  	// append 9p shared volume to storages only if filesystem sharing is supported
   955  	if caps.IsFsSharingSupported() {
   956  		// We mount the shared directory in a predefined location
   957  		// in the guest.
   958  		// This is where at least some of the host config files
   959  		// (resolv.conf, etc...) and potentially all container
   960  		// rootfs will reside.
   961  		if sandbox.config.HypervisorConfig.SharedFS == config.VirtioFS {
   962  			// If virtio-fs uses either of the two cache options 'auto, always',
   963  			// the guest directory can be mounted with option 'dax' allowing it to
   964  			// directly map contents from the host. When set to 'none', the mount
   965  			// options should not contain 'dax' lest the virtio-fs daemon crashing
   966  			// with an invalid address reference.
   967  			if sandbox.config.HypervisorConfig.VirtioFSCache != typeVirtioFSNoCache {
   968  				// If virtio_fs_cache_size = 0, dax should not be used.
   969  				if sandbox.config.HypervisorConfig.VirtioFSCacheSize != 0 {
   970  					sharedDirVirtioFSOptions = append(sharedDirVirtioFSOptions, sharedDirVirtioFSDaxOptions)
   971  				}
   972  			}
   973  			sharedVolume := &grpc.Storage{
   974  				Driver:     kataVirtioFSDevType,
   975  				Source:     mountGuestTag,
   976  				MountPoint: kataGuestSharedDir(),
   977  				Fstype:     typeVirtioFS,
   978  				Options:    sharedDirVirtioFSOptions,
   979  			}
   980  
   981  			storages = append(storages, sharedVolume)
   982  		} else {
   983  			sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
   984  
   985  			sharedVolume := &grpc.Storage{
   986  				Driver:     kata9pDevType,
   987  				Source:     mountGuestTag,
   988  				MountPoint: kataGuestSharedDir(),
   989  				Fstype:     type9pFs,
   990  				Options:    sharedDir9pOptions,
   991  			}
   992  
   993  			storages = append(storages, sharedVolume)
   994  		}
   995  	}
   996  
   997  	if sandbox.shmSize > 0 {
   998  		path := filepath.Join(kataGuestSandboxDir(), shmDir)
   999  		shmSizeOption := fmt.Sprintf("size=%d", sandbox.shmSize)
  1000  
  1001  		shmStorage := &grpc.Storage{
  1002  			Driver:     KataEphemeralDevType,
  1003  			MountPoint: path,
  1004  			Source:     "shm",
  1005  			Fstype:     "tmpfs",
  1006  			Options:    []string{"noexec", "nosuid", "nodev", "mode=1777", shmSizeOption},
  1007  		}
  1008  
  1009  		storages = append(storages, shmStorage)
  1010  	}
  1011  
  1012  	return storages
  1013  }
  1014  
  1015  func (k *kataAgent) stopSandbox(sandbox *Sandbox) error {
  1016  	span, _ := k.trace("stopSandbox")
  1017  	defer span.Finish()
  1018  
  1019  	if k.proxy == nil {
  1020  		return errorMissingProxy
  1021  	}
  1022  
  1023  	req := &grpc.DestroySandboxRequest{}
  1024  
  1025  	if _, err := k.sendReq(req); err != nil {
  1026  		return err
  1027  	}
  1028  
  1029  	if k.dynamicTracing {
  1030  		_, err := k.sendReq(&grpc.StopTracingRequest{})
  1031  		if err != nil {
  1032  			return err
  1033  		}
  1034  	}
  1035  
  1036  	if err := k.proxy.stop(k.state.ProxyPid); err != nil {
  1037  		return err
  1038  	}
  1039  
  1040  	// clean up agent state
  1041  	k.state.ProxyPid = -1
  1042  	k.state.URL = ""
  1043  	return nil
  1044  }
  1045  
  1046  func (k *kataAgent) replaceOCIMountSource(spec *specs.Spec, guestMounts map[string]Mount) error {
  1047  	ociMounts := spec.Mounts
  1048  
  1049  	for index, m := range ociMounts {
  1050  		if guestMount, ok := guestMounts[m.Destination]; ok {
  1051  			k.Logger().Debugf("Replacing OCI mount (%s) source %s with %s", m.Destination, m.Source, guestMount.Source)
  1052  			ociMounts[index].Source = guestMount.Source
  1053  		}
  1054  	}
  1055  
  1056  	return nil
  1057  }
  1058  
  1059  func (k *kataAgent) removeIgnoredOCIMount(spec *specs.Spec, ignoredMounts map[string]Mount) error {
  1060  	var mounts []specs.Mount
  1061  
  1062  	for _, m := range spec.Mounts {
  1063  		if _, found := ignoredMounts[m.Source]; found {
  1064  			k.Logger().WithField("removed-mount", m.Source).Debug("Removing OCI mount")
  1065  		} else {
  1066  			mounts = append(mounts, m)
  1067  		}
  1068  	}
  1069  
  1070  	// Replace the OCI mounts with the updated list.
  1071  	spec.Mounts = mounts
  1072  
  1073  	return nil
  1074  }
  1075  
  1076  func (k *kataAgent) replaceOCIMountsForStorages(spec *specs.Spec, volumeStorages []*grpc.Storage) error {
  1077  	ociMounts := spec.Mounts
  1078  	var index int
  1079  	var m specs.Mount
  1080  
  1081  	for i, v := range volumeStorages {
  1082  		for index, m = range ociMounts {
  1083  			if m.Destination != v.MountPoint {
  1084  				continue
  1085  			}
  1086  
  1087  			// Create a temporary location to mount the Storage. Mounting to the correct location
  1088  			// will be handled by the OCI mount structure.
  1089  			filename := fmt.Sprintf("%s-%s", uuid.Generate().String(), filepath.Base(m.Destination))
  1090  			path := filepath.Join(kataGuestSandboxStorageDir(), filename)
  1091  
  1092  			k.Logger().Debugf("Replacing OCI mount source (%s) with %s", m.Source, path)
  1093  			ociMounts[index].Source = path
  1094  			volumeStorages[i].MountPoint = path
  1095  
  1096  			break
  1097  		}
  1098  		if index == len(ociMounts) {
  1099  			return fmt.Errorf("OCI mount not found for block volume %s", v.MountPoint)
  1100  		}
  1101  	}
  1102  	return nil
  1103  }
  1104  
  1105  func (k *kataAgent) constraintGRPCSpec(grpcSpec *grpc.Spec, passSeccomp bool) {
  1106  	// Disable Hooks since they have been handled on the host and there is
  1107  	// no reason to send them to the agent. It would make no sense to try
  1108  	// to apply them on the guest.
  1109  	grpcSpec.Hooks = nil
  1110  
  1111  	// Pass seccomp only if disable_guest_seccomp is set to false in
  1112  	// configuration.toml and guest image is seccomp capable.
  1113  	if !passSeccomp {
  1114  		grpcSpec.Linux.Seccomp = nil
  1115  	}
  1116  
  1117  	// Disable SELinux inside of the virtual machine, the label will apply
  1118  	// to the KVM process
  1119  	if grpcSpec.Process.SelinuxLabel != "" {
  1120  		k.Logger().Info("SELinux label from config will be applied to the hypervisor process, not the VM workload")
  1121  		grpcSpec.Process.SelinuxLabel = ""
  1122  	}
  1123  
  1124  	// By now only CPU constraints are supported
  1125  	// Issue: https://github.com/kata-containers/runtime/issues/158
  1126  	// Issue: https://github.com/kata-containers/runtime/issues/204
  1127  	grpcSpec.Linux.Resources.Devices = nil
  1128  	grpcSpec.Linux.Resources.Pids = nil
  1129  	grpcSpec.Linux.Resources.BlockIO = nil
  1130  	grpcSpec.Linux.Resources.HugepageLimits = nil
  1131  	grpcSpec.Linux.Resources.Network = nil
  1132  	if grpcSpec.Linux.Resources.CPU != nil {
  1133  		grpcSpec.Linux.Resources.CPU.Cpus = ""
  1134  		grpcSpec.Linux.Resources.CPU.Mems = ""
  1135  	}
  1136  
  1137  	// There are three main reasons to do not apply systemd cgroups in the VM
  1138  	// - Initrd image doesn't have systemd.
  1139  	// - Nobody will be able to modify the resources of a specific container by using systemctl set-property.
  1140  	// - docker is not running in the VM.
  1141  	if vccgroups.IsSystemdCgroup(grpcSpec.Linux.CgroupsPath) {
  1142  		// Convert systemd cgroup to cgroupfs
  1143  		slice := strings.Split(grpcSpec.Linux.CgroupsPath, ":")
  1144  		// 0 - slice: system.slice
  1145  		// 1 - prefix: docker
  1146  		// 2 - name: abc123
  1147  		grpcSpec.Linux.CgroupsPath = filepath.Join("/", slice[1], slice[2])
  1148  	}
  1149  
  1150  	// Disable network namespace since it is already handled on the host by
  1151  	// virtcontainers. The network is a complex part which cannot be simply
  1152  	// passed to the agent.
  1153  	// Every other namespaces's paths have to be emptied. This way, there
  1154  	// is no confusion from the agent, trying to find an existing namespace
  1155  	// on the guest.
  1156  	var tmpNamespaces []grpc.LinuxNamespace
  1157  	for _, ns := range grpcSpec.Linux.Namespaces {
  1158  		switch ns.Type {
  1159  		case specs.CgroupNamespace:
  1160  		case specs.NetworkNamespace:
  1161  		default:
  1162  			ns.Path = ""
  1163  			tmpNamespaces = append(tmpNamespaces, ns)
  1164  		}
  1165  	}
  1166  	grpcSpec.Linux.Namespaces = tmpNamespaces
  1167  
  1168  	// VFIO char device shouldn't not appear in the guest,
  1169  	// the device driver should handle it and determinate its group.
  1170  	var linuxDevices []grpc.LinuxDevice
  1171  	for _, dev := range grpcSpec.Linux.Devices {
  1172  		if dev.Type == "c" && strings.HasPrefix(dev.Path, vfioPath) {
  1173  			k.Logger().WithField("vfio-dev", dev.Path).Debug("removing vfio device from grpcSpec")
  1174  			continue
  1175  		}
  1176  		linuxDevices = append(linuxDevices, dev)
  1177  	}
  1178  	grpcSpec.Linux.Devices = linuxDevices
  1179  }
  1180  
  1181  func (k *kataAgent) handleShm(mounts []specs.Mount, sandbox *Sandbox) {
  1182  	for idx, mnt := range mounts {
  1183  		if mnt.Destination != "/dev/shm" {
  1184  			continue
  1185  		}
  1186  
  1187  		// If /dev/shm for a container is backed by an ephemeral volume, skip
  1188  		// bind-mounting it to the sandbox shm.
  1189  		// A later call to handleEphemeralStorage should take care of setting up /dev/shm correctly.
  1190  		if mnt.Type == KataEphemeralDevType {
  1191  			continue
  1192  		}
  1193  
  1194  		// A container shm mount is shared with sandbox shm mount.
  1195  		if sandbox.shmSize > 0 {
  1196  			mounts[idx].Type = "bind"
  1197  			mounts[idx].Options = []string{"rbind"}
  1198  			mounts[idx].Source = filepath.Join(kataGuestSandboxDir(), shmDir)
  1199  			k.Logger().WithField("shm-size", sandbox.shmSize).Info("Using sandbox shm")
  1200  		} else {
  1201  			// This should typically not happen, as a sandbox shm mount is always set up by the
  1202  			// upper stack.
  1203  			sizeOption := fmt.Sprintf("size=%d", DefaultShmSize)
  1204  			mounts[idx].Type = "tmpfs"
  1205  			mounts[idx].Source = "shm"
  1206  			mounts[idx].Options = []string{"noexec", "nosuid", "nodev", "mode=1777", sizeOption}
  1207  			k.Logger().WithField("shm-size", sizeOption).Info("Setting up a separate shm for container")
  1208  		}
  1209  	}
  1210  }
  1211  
  1212  func (k *kataAgent) appendBlockDevice(dev ContainerDevice, c *Container) *grpc.Device {
  1213  	device := c.sandbox.devManager.GetDeviceByID(dev.ID)
  1214  
  1215  	d, ok := device.GetDeviceInfo().(*config.BlockDrive)
  1216  	if !ok || d == nil {
  1217  		k.Logger().WithField("device", device).Error("malformed block drive")
  1218  		return nil
  1219  	}
  1220  
  1221  	if d.Pmem {
  1222  		// block drive is a persistent memory device that
  1223  		// was passed as volume (-v) not as device (--device).
  1224  		// It shouldn't be visible in the container
  1225  		return nil
  1226  	}
  1227  
  1228  	kataDevice := &grpc.Device{
  1229  		ContainerPath: dev.ContainerPath,
  1230  	}
  1231  
  1232  	switch c.sandbox.config.HypervisorConfig.BlockDeviceDriver {
  1233  	case config.VirtioMmio:
  1234  		kataDevice.Type = kataMmioBlkDevType
  1235  		kataDevice.Id = d.VirtPath
  1236  		kataDevice.VmPath = d.VirtPath
  1237  	case config.VirtioBlockCCW:
  1238  		kataDevice.Type = kataBlkCCWDevType
  1239  		kataDevice.Id = d.DevNo
  1240  	case config.VirtioBlock:
  1241  		kataDevice.Type = kataBlkDevType
  1242  		kataDevice.Id = d.PCIPath.String()
  1243  		kataDevice.VmPath = d.VirtPath
  1244  	case config.VirtioSCSI:
  1245  		kataDevice.Type = kataSCSIDevType
  1246  		kataDevice.Id = d.SCSIAddr
  1247  	case config.Nvdimm:
  1248  		kataDevice.Type = kataNvdimmDevType
  1249  		kataDevice.VmPath = fmt.Sprintf("/dev/pmem%s", d.NvdimmID)
  1250  	}
  1251  
  1252  	return kataDevice
  1253  }
  1254  
  1255  func (k *kataAgent) appendVhostUserBlkDevice(dev ContainerDevice, c *Container) *grpc.Device {
  1256  	device := c.sandbox.devManager.GetDeviceByID(dev.ID)
  1257  
  1258  	d, ok := device.GetDeviceInfo().(*config.VhostUserDeviceAttrs)
  1259  	if !ok || d == nil {
  1260  		k.Logger().WithField("device", device).Error("malformed vhost-user-blk drive")
  1261  		return nil
  1262  	}
  1263  
  1264  	kataDevice := &grpc.Device{
  1265  		ContainerPath: dev.ContainerPath,
  1266  		Type:          kataBlkDevType,
  1267  		Id:            d.PCIPath.String(),
  1268  	}
  1269  
  1270  	return kataDevice
  1271  }
  1272  
  1273  func (k *kataAgent) appendDevices(deviceList []*grpc.Device, c *Container) []*grpc.Device {
  1274  	var kataDevice *grpc.Device
  1275  
  1276  	for _, dev := range c.devices {
  1277  		device := c.sandbox.devManager.GetDeviceByID(dev.ID)
  1278  		if device == nil {
  1279  			k.Logger().WithField("device", dev.ID).Error("failed to find device by id")
  1280  			return nil
  1281  		}
  1282  
  1283  		switch device.DeviceType() {
  1284  		case config.DeviceBlock:
  1285  			kataDevice = k.appendBlockDevice(dev, c)
  1286  		case config.VhostUserBlk:
  1287  			kataDevice = k.appendVhostUserBlkDevice(dev, c)
  1288  		}
  1289  
  1290  		if kataDevice == nil {
  1291  			continue
  1292  		}
  1293  
  1294  		deviceList = append(deviceList, kataDevice)
  1295  	}
  1296  
  1297  	return deviceList
  1298  }
  1299  
  1300  // rollbackFailingContainerCreation rolls back important steps that might have
  1301  // been performed before the container creation failed.
  1302  // - Unmount container volumes.
  1303  // - Unmount container rootfs.
  1304  func (k *kataAgent) rollbackFailingContainerCreation(c *Container) {
  1305  	if c != nil {
  1306  		if err2 := c.unmountHostMounts(); err2 != nil {
  1307  			k.Logger().WithError(err2).Error("rollback failed unmountHostMounts()")
  1308  		}
  1309  
  1310  		if err2 := bindUnmountContainerRootfs(k.ctx, getMountPath(c.sandbox.id), c); err2 != nil {
  1311  			k.Logger().WithError(err2).Error("rollback failed bindUnmountContainerRootfs()")
  1312  		}
  1313  	}
  1314  }
  1315  
  1316  func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) {
  1317  	if c.state.Fstype != "" && c.state.BlockDeviceID != "" {
  1318  		// The rootfs storage volume represents the container rootfs
  1319  		// mount point inside the guest.
  1320  		// It can be a block based device (when using block based container
  1321  		// overlay on the host) mount or a 9pfs one (for all other overlay
  1322  		// implementations).
  1323  		rootfs := &grpc.Storage{}
  1324  
  1325  		// This is a block based device rootfs.
  1326  		device := sandbox.devManager.GetDeviceByID(c.state.BlockDeviceID)
  1327  		if device == nil {
  1328  			k.Logger().WithField("device", c.state.BlockDeviceID).Error("failed to find device by id")
  1329  			return nil, fmt.Errorf("failed to find device by id %q", c.state.BlockDeviceID)
  1330  		}
  1331  
  1332  		blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive)
  1333  		if !ok || blockDrive == nil {
  1334  			k.Logger().Error("malformed block drive")
  1335  			return nil, fmt.Errorf("malformed block drive")
  1336  		}
  1337  		switch {
  1338  		case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio:
  1339  			rootfs.Driver = kataMmioBlkDevType
  1340  			rootfs.Source = blockDrive.VirtPath
  1341  		case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlockCCW:
  1342  			rootfs.Driver = kataBlkCCWDevType
  1343  			rootfs.Source = blockDrive.DevNo
  1344  		case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock:
  1345  			rootfs.Driver = kataBlkDevType
  1346  			if blockDrive.PCIPath.IsNil() {
  1347  				rootfs.Source = blockDrive.VirtPath
  1348  			} else {
  1349  				rootfs.Source = blockDrive.PCIPath.String()
  1350  			}
  1351  
  1352  		case sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioSCSI:
  1353  			rootfs.Driver = kataSCSIDevType
  1354  			rootfs.Source = blockDrive.SCSIAddr
  1355  		default:
  1356  			return nil, fmt.Errorf("Unknown block device driver: %s", sandbox.config.HypervisorConfig.BlockDeviceDriver)
  1357  		}
  1358  
  1359  		rootfs.MountPoint = rootPathParent
  1360  		rootfs.Fstype = c.state.Fstype
  1361  
  1362  		if c.state.Fstype == "xfs" {
  1363  			rootfs.Options = []string{"nouuid"}
  1364  		}
  1365  
  1366  		// Ensure container mount destination exists
  1367  		// TODO: remove dependency on shared fs path. shared fs is just one kind of storage source.
  1368  		// we should not always use shared fs path for all kinds of storage. Instead, all storage
  1369  		// should be bind mounted to a tmpfs path for containers to use.
  1370  		if err := os.MkdirAll(filepath.Join(getMountPath(c.sandbox.id), c.id, c.rootfsSuffix), DirMode); err != nil {
  1371  			return nil, err
  1372  		}
  1373  		return rootfs, nil
  1374  	}
  1375  
  1376  	// This is not a block based device rootfs. We are going to bind mount it into the shared drive
  1377  	// between the host and the guest.
  1378  	// With virtiofs/9pfs we don't need to ask the agent to mount the rootfs as the shared directory
  1379  	// (kataGuestSharedDir) is already mounted in the guest. We only need to mount the rootfs from
  1380  	// the host and it will show up in the guest.
  1381  	if err := bindMountContainerRootfs(k.ctx, getMountPath(sandbox.id), c.id, c.rootFs.Target, false); err != nil {
  1382  		return nil, err
  1383  	}
  1384  
  1385  	return nil, nil
  1386  }
  1387  
  1388  func (k *kataAgent) hasAgentDebugConsole(sandbox *Sandbox) bool {
  1389  	for _, p := range sandbox.config.HypervisorConfig.KernelParams {
  1390  		if p.Key == "agent.debug_console" {
  1391  			k.Logger().Info("agent has debug console")
  1392  			return true
  1393  		}
  1394  	}
  1395  	return false
  1396  }
  1397  
  1398  func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process, err error) {
  1399  	span, _ := k.trace("createContainer")
  1400  	defer span.Finish()
  1401  
  1402  	var ctrStorages []*grpc.Storage
  1403  	var ctrDevices []*grpc.Device
  1404  	var rootfs *grpc.Storage
  1405  
  1406  	// This is the guest absolute root path for that container.
  1407  	rootPathParent := filepath.Join(kataGuestSharedDir(), c.id)
  1408  	rootPath := filepath.Join(rootPathParent, c.rootfsSuffix)
  1409  
  1410  	// In case the container creation fails, the following defer statement
  1411  	// takes care of rolling back actions previously performed.
  1412  	defer func() {
  1413  		if err != nil {
  1414  			k.Logger().WithError(err).Error("createContainer failed")
  1415  			k.rollbackFailingContainerCreation(c)
  1416  		}
  1417  	}()
  1418  
  1419  	// setup rootfs -- if its block based, we'll receive a non-nil storage object representing
  1420  	// the block device for the rootfs, which us utilized for mounting in the guest. This'll be handled
  1421  	// already for non-block based rootfs
  1422  	if rootfs, err = k.buildContainerRootfs(sandbox, c, rootPathParent); err != nil {
  1423  		return nil, err
  1424  	}
  1425  
  1426  	if rootfs != nil {
  1427  		// Add rootfs to the list of container storage.
  1428  		// We only need to do this for block based rootfs, as we
  1429  		// want the agent to mount it into the right location
  1430  		// (kataGuestSharedDir/ctrID/
  1431  		ctrStorages = append(ctrStorages, rootfs)
  1432  	}
  1433  
  1434  	ociSpec := c.GetPatchedOCISpec()
  1435  	if ociSpec == nil {
  1436  		return nil, errorMissingOCISpec
  1437  	}
  1438  
  1439  	// Handle container mounts
  1440  	newMounts, ignoredMounts, err := c.mountSharedDirMounts(getSharePath(sandbox.id), getMountPath(sandbox.id), kataGuestSharedDir())
  1441  	if err != nil {
  1442  		return nil, err
  1443  	}
  1444  
  1445  	k.handleShm(ociSpec.Mounts, sandbox)
  1446  
  1447  	epheStorages := k.handleEphemeralStorage(ociSpec.Mounts)
  1448  	ctrStorages = append(ctrStorages, epheStorages...)
  1449  
  1450  	k.Logger().WithField("ociSpec Hugepage Resources", ociSpec.Linux.Resources.HugepageLimits).Debug("ociSpec HugepageLimit")
  1451  	hugepages, err := k.handleHugepages(ociSpec.Mounts, ociSpec.Linux.Resources.HugepageLimits)
  1452  	if err != nil {
  1453  		return nil, err
  1454  	}
  1455  	ctrStorages = append(ctrStorages, hugepages...)
  1456  
  1457  	localStorages := k.handleLocalStorage(ociSpec.Mounts, sandbox.id, c.rootfsSuffix)
  1458  	ctrStorages = append(ctrStorages, localStorages...)
  1459  
  1460  	// We replace all OCI mount sources that match our container mount
  1461  	// with the right source path (The guest one).
  1462  	if err = k.replaceOCIMountSource(ociSpec, newMounts); err != nil {
  1463  		return nil, err
  1464  	}
  1465  
  1466  	// Remove all mounts that should be ignored from the spec
  1467  	if err = k.removeIgnoredOCIMount(ociSpec, ignoredMounts); err != nil {
  1468  		return nil, err
  1469  	}
  1470  
  1471  	// Append container devices for block devices passed with --device.
  1472  	ctrDevices = k.appendDevices(ctrDevices, c)
  1473  
  1474  	// Handle all the volumes that are block device files.
  1475  	// Note this call modifies the list of container devices to make sure
  1476  	// all hotplugged devices are unplugged, so this needs be done
  1477  	// after devices passed with --device are handled.
  1478  	volumeStorages, err := k.handleBlockVolumes(c)
  1479  	if err != nil {
  1480  		return nil, err
  1481  	}
  1482  
  1483  	if err := k.replaceOCIMountsForStorages(ociSpec, volumeStorages); err != nil {
  1484  		return nil, err
  1485  	}
  1486  
  1487  	ctrStorages = append(ctrStorages, volumeStorages...)
  1488  
  1489  	grpcSpec, err := grpc.OCItoGRPC(ociSpec)
  1490  	if err != nil {
  1491  		return nil, err
  1492  	}
  1493  
  1494  	// We need to give the OCI spec our absolute rootfs path in the guest.
  1495  	grpcSpec.Root.Path = rootPath
  1496  
  1497  	sharedPidNs := k.handlePidNamespace(grpcSpec, sandbox)
  1498  
  1499  	agentPidNs := k.checkAgentPidNs(c)
  1500  	if agentPidNs {
  1501  		if !sandbox.config.EnableAgentPidNs {
  1502  			agentPidNs = false
  1503  			k.Logger().Warn("Env variable for sharing container pid namespace with the agent set, but the runtime configuration does not allow this")
  1504  		} else {
  1505  			k.Logger().Warn("Container will share PID namespace with the agent")
  1506  		}
  1507  	}
  1508  	passSeccomp := !sandbox.config.DisableGuestSeccomp && sandbox.seccompSupported
  1509  
  1510  	// We need to constraint the spec to make sure we're not passing
  1511  	// irrelevant information to the agent.
  1512  	k.constraintGRPCSpec(grpcSpec, passSeccomp)
  1513  
  1514  	req := &grpc.CreateContainerRequest{
  1515  		ContainerId:  c.id,
  1516  		ExecId:       c.id,
  1517  		Storages:     ctrStorages,
  1518  		Devices:      ctrDevices,
  1519  		OCI:          grpcSpec,
  1520  		SandboxPidns: sharedPidNs,
  1521  		AgentPidns:   agentPidNs,
  1522  	}
  1523  
  1524  	if _, err = k.sendReq(req); err != nil {
  1525  		return nil, err
  1526  	}
  1527  
  1528  	createNSList := []ns.NSType{ns.NSTypePID}
  1529  
  1530  	enterNSList := []ns.Namespace{}
  1531  	if sandbox.networkNS.NetNsPath != "" {
  1532  		enterNSList = append(enterNSList, ns.Namespace{
  1533  			Path: sandbox.networkNS.NetNsPath,
  1534  			Type: ns.NSTypeNet,
  1535  		})
  1536  	}
  1537  
  1538  	// Ask to the shim to print the agent logs, if it's the process who monitors the sandbox and use_vsock is true (no proxy)
  1539  	// Don't read the console socket if agent debug console is enabled.
  1540  	var consoleURL string
  1541  	if sandbox.config.HypervisorConfig.UseVSock &&
  1542  		c.GetAnnotations()[vcAnnotations.ContainerTypeKey] == string(PodSandbox) &&
  1543  		!k.hasAgentDebugConsole(sandbox) {
  1544  		consoleURL, err = sandbox.hypervisor.getSandboxConsole(sandbox.id)
  1545  		if err != nil {
  1546  			return nil, err
  1547  		}
  1548  	}
  1549  
  1550  	return prepareAndStartShim(sandbox, k.shim, c.id, req.ExecId,
  1551  		k.state.URL, consoleURL, c.config.Cmd, createNSList, enterNSList)
  1552  }
  1553  
  1554  // handleEphemeralStorage handles ephemeral storages by
  1555  // creating a Storage from corresponding source of the mount point
  1556  func (k *kataAgent) handleEphemeralStorage(mounts []specs.Mount) []*grpc.Storage {
  1557  	var epheStorages []*grpc.Storage
  1558  	for idx, mnt := range mounts {
  1559  		if mnt.Type == KataEphemeralDevType {
  1560  			// Set the mount source path to a path that resides inside the VM
  1561  			mounts[idx].Source = filepath.Join(ephemeralPath(), filepath.Base(mnt.Source))
  1562  			// Set the mount type to "bind"
  1563  			mounts[idx].Type = "bind"
  1564  
  1565  			// Create a storage struct so that kata agent is able to create
  1566  			// tmpfs backed volume inside the VM
  1567  			epheStorage := &grpc.Storage{
  1568  				Driver:     KataEphemeralDevType,
  1569  				Source:     "tmpfs",
  1570  				Fstype:     "tmpfs",
  1571  				MountPoint: mounts[idx].Source,
  1572  			}
  1573  			epheStorages = append(epheStorages, epheStorage)
  1574  		}
  1575  	}
  1576  	return epheStorages
  1577  }
  1578  
  1579  // handleHugePages handles hugepages storage by
  1580  // creating a Storage from corresponding source of the mount point
  1581  func (k *kataAgent) handleHugepages(mounts []specs.Mount, hugepageLimits []specs.LinuxHugepageLimit) ([]*grpc.Storage, error) {
  1582  	//Map to hold the total memory of each type of hugepages
  1583  	optionsMap := make(map[int64]string)
  1584  
  1585  	for _, hp := range hugepageLimits {
  1586  		if hp.Limit != 0 {
  1587  			k.Logger().WithFields(logrus.Fields{
  1588  				"Pagesize": hp.Pagesize,
  1589  				"Limit":    hp.Limit,
  1590  			}).Info("hugepage request")
  1591  			//example Pagesize 2MB, 1GB etc. The Limit are in Bytes
  1592  			pageSize, err := units.RAMInBytes(hp.Pagesize)
  1593  			if err != nil {
  1594  				k.Logger().Error("Unable to convert pagesize to bytes")
  1595  				return nil, err
  1596  			}
  1597  			totalHpSizeStr := strconv.FormatUint(hp.Limit, 10)
  1598  			optionsMap[pageSize] = totalHpSizeStr
  1599  		}
  1600  	}
  1601  
  1602  	var hugepages []*grpc.Storage
  1603  	for idx, mnt := range mounts {
  1604  		if mnt.Type != KataLocalDevType {
  1605  			continue
  1606  		}
  1607  		//HugePages mount Type is Local
  1608  		if _, fsType, fsOptions, _ := utils.GetDevicePathAndFsTypeOptions(mnt.Source); fsType == "hugetlbfs" {
  1609  			k.Logger().WithField("fsOptions", fsOptions).Debug("hugepage mount options")
  1610  			//Find the pagesize from the mountpoint options
  1611  			pagesizeOpt := getPagesizeFromOpt(fsOptions)
  1612  			if pagesizeOpt == "" {
  1613  				return nil, fmt.Errorf("No pagesize option found in filesystem mount options")
  1614  			}
  1615  			pageSize, err := units.RAMInBytes(pagesizeOpt)
  1616  			if err != nil {
  1617  				k.Logger().Error("Unable to convert pagesize from fs mount options to bytes")
  1618  				return nil, err
  1619  			}
  1620  			//Create mount option string
  1621  			options := fmt.Sprintf("pagesize=%s,size=%s", strconv.FormatInt(pageSize, 10), optionsMap[pageSize])
  1622  			k.Logger().WithField("Hugepage options string", options).Debug("hugepage mount options")
  1623  			// Set the mount source path to a path that resides inside the VM
  1624  			mounts[idx].Source = filepath.Join(ephemeralPath(), filepath.Base(mnt.Source))
  1625  			// Set the mount type to "bind"
  1626  			mounts[idx].Type = "bind"
  1627  
  1628  			// Create a storage struct so that kata agent is able to create
  1629  			// hugetlbfs backed volume inside the VM
  1630  			hugepage := &grpc.Storage{
  1631  				Driver:     KataEphemeralDevType,
  1632  				Source:     "nodev",
  1633  				Fstype:     "hugetlbfs",
  1634  				MountPoint: mounts[idx].Source,
  1635  				Options:    []string{options},
  1636  			}
  1637  			hugepages = append(hugepages, hugepage)
  1638  		}
  1639  
  1640  	}
  1641  	return hugepages, nil
  1642  }
  1643  
  1644  // handleLocalStorage handles local storage within the VM
  1645  // by creating a directory in the VM from the source of the mount point.
  1646  func (k *kataAgent) handleLocalStorage(mounts []specs.Mount, sandboxID string, rootfsSuffix string) []*grpc.Storage {
  1647  	var localStorages []*grpc.Storage
  1648  	for idx, mnt := range mounts {
  1649  		if mnt.Type == KataLocalDevType {
  1650  			// Set the mount source path to a the desired directory point in the VM.
  1651  			// In this case it is located in the sandbox directory.
  1652  			// We rely on the fact that the first container in the VM has the same ID as the sandbox ID.
  1653  			// In Kubernetes, this is usually the pause container and we depend on it existing for
  1654  			// local directories to work.
  1655  			mounts[idx].Source = filepath.Join(kataGuestSharedDir(), sandboxID, rootfsSuffix, KataLocalDevType, filepath.Base(mnt.Source))
  1656  
  1657  			// Create a storage struct so that the kata agent is able to create the
  1658  			// directory inside the VM.
  1659  			localStorage := &grpc.Storage{
  1660  				Driver:     KataLocalDevType,
  1661  				Source:     KataLocalDevType,
  1662  				Fstype:     KataLocalDevType,
  1663  				MountPoint: mounts[idx].Source,
  1664  				Options:    localDirOptions,
  1665  			}
  1666  			localStorages = append(localStorages, localStorage)
  1667  		}
  1668  	}
  1669  	return localStorages
  1670  }
  1671  
  1672  // handleDeviceBlockVolume handles volume that is block device file
  1673  // and DeviceBlock type.
  1674  func (k *kataAgent) handleDeviceBlockVolume(c *Container, m Mount, device api.Device) (*grpc.Storage, error) {
  1675  	vol := &grpc.Storage{}
  1676  
  1677  	blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive)
  1678  	if !ok || blockDrive == nil {
  1679  		k.Logger().Error("malformed block drive")
  1680  		return nil, fmt.Errorf("malformed block drive")
  1681  	}
  1682  	switch {
  1683  	// pmem volumes case
  1684  	case blockDrive.Pmem:
  1685  		vol.Driver = kataNvdimmDevType
  1686  		vol.Source = fmt.Sprintf("/dev/pmem%s", blockDrive.NvdimmID)
  1687  		vol.Fstype = blockDrive.Format
  1688  		vol.Options = []string{"dax"}
  1689  	case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlockCCW:
  1690  		vol.Driver = kataBlkCCWDevType
  1691  		vol.Source = blockDrive.DevNo
  1692  	case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock:
  1693  		vol.Driver = kataBlkDevType
  1694  		if blockDrive.PCIPath.IsNil() {
  1695  			vol.Source = blockDrive.VirtPath
  1696  		} else {
  1697  			vol.Source = blockDrive.PCIPath.String()
  1698  		}
  1699  	case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio:
  1700  		vol.Driver = kataMmioBlkDevType
  1701  		vol.Source = blockDrive.VirtPath
  1702  	case c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioSCSI:
  1703  		vol.Driver = kataSCSIDevType
  1704  		vol.Source = blockDrive.SCSIAddr
  1705  	default:
  1706  		return nil, fmt.Errorf("Unknown block device driver: %s", c.sandbox.config.HypervisorConfig.BlockDeviceDriver)
  1707  	}
  1708  
  1709  	vol.MountPoint = m.Destination
  1710  
  1711  	// If no explicit FS Type or Options are being set, then let's use what is provided for the particular mount:
  1712  	if vol.Fstype == "" {
  1713  		vol.Fstype = m.Type
  1714  	}
  1715  	if len(vol.Options) == 0 {
  1716  		vol.Options = m.Options
  1717  	}
  1718  
  1719  	return vol, nil
  1720  }
  1721  
  1722  // handleVhostUserBlkVolume handles volume that is block device file
  1723  // and VhostUserBlk type.
  1724  func (k *kataAgent) handleVhostUserBlkVolume(c *Container, m Mount, device api.Device) (*grpc.Storage, error) {
  1725  	vol := &grpc.Storage{}
  1726  
  1727  	d, ok := device.GetDeviceInfo().(*config.VhostUserDeviceAttrs)
  1728  	if !ok || d == nil {
  1729  		k.Logger().Error("malformed vhost-user blk drive")
  1730  		return nil, fmt.Errorf("malformed vhost-user blk drive")
  1731  	}
  1732  
  1733  	vol.Driver = kataBlkDevType
  1734  	vol.Source = d.PCIPath.String()
  1735  	vol.Fstype = "bind"
  1736  	vol.Options = []string{"bind"}
  1737  	vol.MountPoint = m.Destination
  1738  
  1739  	return vol, nil
  1740  }
  1741  
  1742  // handleBlockVolumes handles volumes that are block devices files
  1743  // by passing the block devices as Storage to the agent.
  1744  func (k *kataAgent) handleBlockVolumes(c *Container) ([]*grpc.Storage, error) {
  1745  
  1746  	var volumeStorages []*grpc.Storage
  1747  
  1748  	for _, m := range c.mounts {
  1749  		id := m.BlockDeviceID
  1750  
  1751  		if len(id) == 0 {
  1752  			continue
  1753  		}
  1754  
  1755  		// Add the block device to the list of container devices, to make sure the
  1756  		// device is detached with detachDevices() for a container.
  1757  		c.devices = append(c.devices, ContainerDevice{ID: id, ContainerPath: m.Destination})
  1758  
  1759  		var vol *grpc.Storage
  1760  
  1761  		device := c.sandbox.devManager.GetDeviceByID(id)
  1762  		if device == nil {
  1763  			k.Logger().WithField("device", id).Error("failed to find device by id")
  1764  			return nil, fmt.Errorf("Failed to find device by id (id=%s)", id)
  1765  		}
  1766  
  1767  		var err error
  1768  		switch device.DeviceType() {
  1769  		case config.DeviceBlock:
  1770  			vol, err = k.handleDeviceBlockVolume(c, m, device)
  1771  		case config.VhostUserBlk:
  1772  			vol, err = k.handleVhostUserBlkVolume(c, m, device)
  1773  		default:
  1774  			k.Logger().Error("Unknown device type")
  1775  			continue
  1776  		}
  1777  
  1778  		if vol == nil || err != nil {
  1779  			return nil, err
  1780  		}
  1781  
  1782  		volumeStorages = append(volumeStorages, vol)
  1783  	}
  1784  
  1785  	return volumeStorages, nil
  1786  }
  1787  
  1788  // handlePidNamespace checks if Pid namespace for a container needs to be shared with its sandbox
  1789  // pid namespace. This function also modifies the grpc spec to remove the pid namespace
  1790  // from the list of namespaces passed to the agent.
  1791  func (k *kataAgent) handlePidNamespace(grpcSpec *grpc.Spec, sandbox *Sandbox) bool {
  1792  	sharedPidNs := false
  1793  	pidIndex := -1
  1794  
  1795  	for i, ns := range grpcSpec.Linux.Namespaces {
  1796  		if ns.Type != string(specs.PIDNamespace) {
  1797  			continue
  1798  		}
  1799  
  1800  		pidIndex = i
  1801  		// host pidns path does not make sense in kata. Let's just align it with
  1802  		// sandbox namespace whenever it is set.
  1803  		if ns.Path != "" {
  1804  			sharedPidNs = true
  1805  		}
  1806  		break
  1807  	}
  1808  
  1809  	// Remove pid namespace.
  1810  	if pidIndex >= 0 {
  1811  		grpcSpec.Linux.Namespaces = append(grpcSpec.Linux.Namespaces[:pidIndex], grpcSpec.Linux.Namespaces[pidIndex+1:]...)
  1812  	}
  1813  
  1814  	return sharedPidNs
  1815  }
  1816  
  1817  // checkAgentPidNs checks if environment variable KATA_AGENT_PIDNS has been set for a containers
  1818  // This variable is used to indicate if the containers pid namespace should be shared
  1819  // with the agent pidns. This approach was taken due to the lack of support for container level annotations.
  1820  func (k *kataAgent) checkAgentPidNs(container *Container) bool {
  1821  	agentPidNs := false
  1822  
  1823  	for _, env := range container.config.Cmd.Envs {
  1824  		if env.Var == agentPidEnv {
  1825  			if val, err := strconv.ParseBool(env.Value); err == nil {
  1826  				agentPidNs = val
  1827  			}
  1828  		}
  1829  	}
  1830  
  1831  	return agentPidNs
  1832  }
  1833  
  1834  func (k *kataAgent) startContainer(sandbox *Sandbox, c *Container) error {
  1835  	span, _ := k.trace("startContainer")
  1836  	defer span.Finish()
  1837  
  1838  	req := &grpc.StartContainerRequest{
  1839  		ContainerId: c.id,
  1840  	}
  1841  
  1842  	_, err := k.sendReq(req)
  1843  	return err
  1844  }
  1845  
  1846  func (k *kataAgent) stopContainer(sandbox *Sandbox, c Container) error {
  1847  	span, _ := k.trace("stopContainer")
  1848  	defer span.Finish()
  1849  
  1850  	_, err := k.sendReq(&grpc.RemoveContainerRequest{ContainerId: c.id})
  1851  	return err
  1852  }
  1853  
  1854  func (k *kataAgent) signalProcess(c *Container, processID string, signal syscall.Signal, all bool) error {
  1855  	execID := processID
  1856  	if all {
  1857  		// kata agent uses empty execId to signal all processes in a container
  1858  		execID = ""
  1859  	}
  1860  	req := &grpc.SignalProcessRequest{
  1861  		ContainerId: c.id,
  1862  		ExecId:      execID,
  1863  		Signal:      uint32(signal),
  1864  	}
  1865  
  1866  	_, err := k.sendReq(req)
  1867  	return err
  1868  }
  1869  
  1870  func (k *kataAgent) winsizeProcess(c *Container, processID string, height, width uint32) error {
  1871  	req := &grpc.TtyWinResizeRequest{
  1872  		ContainerId: c.id,
  1873  		ExecId:      processID,
  1874  		Row:         height,
  1875  		Column:      width,
  1876  	}
  1877  
  1878  	_, err := k.sendReq(req)
  1879  	return err
  1880  }
  1881  
  1882  func (k *kataAgent) processListContainer(sandbox *Sandbox, c Container, options ProcessListOptions) (ProcessList, error) {
  1883  	req := &grpc.ListProcessesRequest{
  1884  		ContainerId: c.id,
  1885  		Format:      options.Format,
  1886  		Args:        options.Args,
  1887  	}
  1888  
  1889  	resp, err := k.sendReq(req)
  1890  	if err != nil {
  1891  		return nil, err
  1892  	}
  1893  
  1894  	processList, ok := resp.(*grpc.ListProcessesResponse)
  1895  	if !ok {
  1896  		return nil, fmt.Errorf("Bad list processes response")
  1897  	}
  1898  
  1899  	return processList.ProcessList, nil
  1900  }
  1901  
  1902  func (k *kataAgent) updateContainer(sandbox *Sandbox, c Container, resources specs.LinuxResources) error {
  1903  	grpcResources, err := grpc.ResourcesOCItoGRPC(&resources)
  1904  	if err != nil {
  1905  		return err
  1906  	}
  1907  
  1908  	req := &grpc.UpdateContainerRequest{
  1909  		ContainerId: c.id,
  1910  		Resources:   grpcResources,
  1911  	}
  1912  
  1913  	_, err = k.sendReq(req)
  1914  	return err
  1915  }
  1916  
  1917  func (k *kataAgent) pauseContainer(sandbox *Sandbox, c Container) error {
  1918  	req := &grpc.PauseContainerRequest{
  1919  		ContainerId: c.id,
  1920  	}
  1921  
  1922  	_, err := k.sendReq(req)
  1923  	return err
  1924  }
  1925  
  1926  func (k *kataAgent) resumeContainer(sandbox *Sandbox, c Container) error {
  1927  	req := &grpc.ResumeContainerRequest{
  1928  		ContainerId: c.id,
  1929  	}
  1930  
  1931  	_, err := k.sendReq(req)
  1932  	return err
  1933  }
  1934  
  1935  func (k *kataAgent) memHotplugByProbe(addr uint64, sizeMB uint32, memorySectionSizeMB uint32) error {
  1936  	if memorySectionSizeMB == uint32(0) {
  1937  		return fmt.Errorf("memorySectionSizeMB couldn't be zero")
  1938  	}
  1939  	// hot-added memory device should be sliced into the size of memory section, which is the basic unit for
  1940  	// memory hotplug
  1941  	numSection := uint64(sizeMB / memorySectionSizeMB)
  1942  	var addrList []uint64
  1943  	index := uint64(0)
  1944  	for index < numSection {
  1945  		k.Logger().WithFields(logrus.Fields{
  1946  			"addr": fmt.Sprintf("0x%x", addr+(index*uint64(memorySectionSizeMB))<<20),
  1947  		}).Debugf("notify guest kernel the address of memory device")
  1948  		addrList = append(addrList, addr+(index*uint64(memorySectionSizeMB))<<20)
  1949  		index++
  1950  	}
  1951  	req := &grpc.MemHotplugByProbeRequest{
  1952  		MemHotplugProbeAddr: addrList,
  1953  	}
  1954  
  1955  	_, err := k.sendReq(req)
  1956  	return err
  1957  }
  1958  
  1959  func (k *kataAgent) onlineCPUMem(cpus uint32, cpuOnly bool) error {
  1960  	req := &grpc.OnlineCPUMemRequest{
  1961  		Wait:    false,
  1962  		NbCpus:  cpus,
  1963  		CpuOnly: cpuOnly,
  1964  	}
  1965  
  1966  	_, err := k.sendReq(req)
  1967  	return err
  1968  }
  1969  
  1970  func (k *kataAgent) statsContainer(sandbox *Sandbox, c Container) (*ContainerStats, error) {
  1971  	req := &grpc.StatsContainerRequest{
  1972  		ContainerId: c.id,
  1973  	}
  1974  
  1975  	returnStats, err := k.sendReq(req)
  1976  
  1977  	if err != nil {
  1978  		return nil, err
  1979  	}
  1980  
  1981  	stats, ok := returnStats.(*grpc.StatsContainerResponse)
  1982  	if !ok {
  1983  		return nil, fmt.Errorf("irregular response container stats")
  1984  	}
  1985  
  1986  	data, err := json.Marshal(stats.CgroupStats)
  1987  	if err != nil {
  1988  		return nil, err
  1989  	}
  1990  
  1991  	var cgroupStats CgroupStats
  1992  	err = json.Unmarshal(data, &cgroupStats)
  1993  	if err != nil {
  1994  		return nil, err
  1995  	}
  1996  	containerStats := &ContainerStats{
  1997  		CgroupStats: &cgroupStats,
  1998  	}
  1999  	return containerStats, nil
  2000  }
  2001  
  2002  func (k *kataAgent) connect() error {
  2003  	if k.dead {
  2004  		return errors.New("Dead agent")
  2005  	}
  2006  	// lockless quick pass
  2007  	if k.client != nil {
  2008  		return nil
  2009  	}
  2010  
  2011  	span, _ := k.trace("connect")
  2012  	defer span.Finish()
  2013  
  2014  	// This is for the first connection only, to prevent race
  2015  	k.Lock()
  2016  	defer k.Unlock()
  2017  	if k.client != nil {
  2018  		return nil
  2019  	}
  2020  
  2021  	if k.state.ProxyPid > 0 {
  2022  		// check that proxy is running before talk with it avoiding long timeouts
  2023  		if err := syscall.Kill(k.state.ProxyPid, syscall.Signal(0)); err != nil {
  2024  			return errors.New("Proxy is not running")
  2025  		}
  2026  	}
  2027  
  2028  	k.Logger().WithField("url", k.state.URL).WithField("proxy", k.state.ProxyPid).Info("New client")
  2029  	client, err := kataclient.NewAgentClient(k.ctx, k.state.URL, k.proxyBuiltIn)
  2030  	if err != nil {
  2031  		k.dead = true
  2032  		return err
  2033  	}
  2034  
  2035  	k.installReqFunc(client)
  2036  	k.client = client
  2037  
  2038  	return nil
  2039  }
  2040  
  2041  func (k *kataAgent) disconnect() error {
  2042  	span, _ := k.trace("disconnect")
  2043  	defer span.Finish()
  2044  
  2045  	k.Lock()
  2046  	defer k.Unlock()
  2047  
  2048  	if k.client == nil {
  2049  		return nil
  2050  	}
  2051  
  2052  	if err := k.client.Close(); err != nil && grpcStatus.Convert(err).Code() != codes.Canceled {
  2053  		return err
  2054  	}
  2055  
  2056  	k.client = nil
  2057  	k.reqHandlers = nil
  2058  
  2059  	return nil
  2060  }
  2061  
  2062  // check grpc server is serving
  2063  func (k *kataAgent) check() error {
  2064  	span, _ := k.trace("check")
  2065  	defer span.Finish()
  2066  
  2067  	_, err := k.sendReq(&grpc.CheckRequest{})
  2068  	if err != nil {
  2069  		err = fmt.Errorf("Failed to check if grpc server is working: %s", err)
  2070  	}
  2071  	return err
  2072  }
  2073  
  2074  func (k *kataAgent) waitProcess(c *Container, processID string) (int32, error) {
  2075  	span, _ := k.trace("waitProcess")
  2076  	defer span.Finish()
  2077  
  2078  	resp, err := k.sendReq(&grpc.WaitProcessRequest{
  2079  		ContainerId: c.id,
  2080  		ExecId:      processID,
  2081  	})
  2082  	if err != nil {
  2083  		return 0, err
  2084  	}
  2085  
  2086  	return resp.(*grpc.WaitProcessResponse).Status, nil
  2087  }
  2088  
  2089  func (k *kataAgent) writeProcessStdin(c *Container, ProcessID string, data []byte) (int, error) {
  2090  	resp, err := k.sendReq(&grpc.WriteStreamRequest{
  2091  		ContainerId: c.id,
  2092  		ExecId:      ProcessID,
  2093  		Data:        data,
  2094  	})
  2095  
  2096  	if err != nil {
  2097  		return 0, err
  2098  	}
  2099  
  2100  	return int(resp.(*grpc.WriteStreamResponse).Len), nil
  2101  }
  2102  
  2103  func (k *kataAgent) closeProcessStdin(c *Container, ProcessID string) error {
  2104  	_, err := k.sendReq(&grpc.CloseStdinRequest{
  2105  		ContainerId: c.id,
  2106  		ExecId:      ProcessID,
  2107  	})
  2108  
  2109  	return err
  2110  }
  2111  
  2112  func (k *kataAgent) reseedRNG(data []byte) error {
  2113  	_, err := k.sendReq(&grpc.ReseedRandomDevRequest{
  2114  		Data: data,
  2115  	})
  2116  
  2117  	return err
  2118  }
  2119  
  2120  type reqFunc func(context.Context, interface{}, ...golangGrpc.CallOption) (interface{}, error)
  2121  
  2122  func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
  2123  	k.reqHandlers = make(map[string]reqFunc)
  2124  	k.reqHandlers[grpcCheckRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2125  		return k.client.Check(ctx, req.(*grpc.CheckRequest), opts...)
  2126  	}
  2127  	k.reqHandlers[grpcExecProcessRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2128  		return k.client.ExecProcess(ctx, req.(*grpc.ExecProcessRequest), opts...)
  2129  	}
  2130  	k.reqHandlers[grpcCreateSandboxRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2131  		return k.client.CreateSandbox(ctx, req.(*grpc.CreateSandboxRequest), opts...)
  2132  	}
  2133  	k.reqHandlers[grpcDestroySandboxRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2134  		return k.client.DestroySandbox(ctx, req.(*grpc.DestroySandboxRequest), opts...)
  2135  	}
  2136  	k.reqHandlers[grpcCreateContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2137  		return k.client.CreateContainer(ctx, req.(*grpc.CreateContainerRequest), opts...)
  2138  	}
  2139  	k.reqHandlers[grpcStartContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2140  		return k.client.StartContainer(ctx, req.(*grpc.StartContainerRequest), opts...)
  2141  	}
  2142  	k.reqHandlers[grpcRemoveContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2143  		return k.client.RemoveContainer(ctx, req.(*grpc.RemoveContainerRequest), opts...)
  2144  	}
  2145  	k.reqHandlers[grpcSignalProcessRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2146  		return k.client.SignalProcess(ctx, req.(*grpc.SignalProcessRequest), opts...)
  2147  	}
  2148  	k.reqHandlers[grpcUpdateRoutesRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2149  		return k.client.UpdateRoutes(ctx, req.(*grpc.UpdateRoutesRequest), opts...)
  2150  	}
  2151  	k.reqHandlers[grpcUpdateInterfaceRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2152  		return k.client.UpdateInterface(ctx, req.(*grpc.UpdateInterfaceRequest), opts...)
  2153  	}
  2154  	k.reqHandlers[grpcListInterfacesRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2155  		return k.client.ListInterfaces(ctx, req.(*grpc.ListInterfacesRequest), opts...)
  2156  	}
  2157  	k.reqHandlers[grpcListRoutesRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2158  		return k.client.ListRoutes(ctx, req.(*grpc.ListRoutesRequest), opts...)
  2159  	}
  2160  	k.reqHandlers[grpcAddARPNeighborsRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2161  		return k.client.AddARPNeighbors(ctx, req.(*grpc.AddARPNeighborsRequest), opts...)
  2162  	}
  2163  	k.reqHandlers[grpcOnlineCPUMemRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2164  		return k.client.OnlineCPUMem(ctx, req.(*grpc.OnlineCPUMemRequest), opts...)
  2165  	}
  2166  	k.reqHandlers[grpcListProcessesRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2167  		return k.client.ListProcesses(ctx, req.(*grpc.ListProcessesRequest), opts...)
  2168  	}
  2169  	k.reqHandlers[grpcUpdateContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2170  		return k.client.UpdateContainer(ctx, req.(*grpc.UpdateContainerRequest), opts...)
  2171  	}
  2172  	k.reqHandlers[grpcWaitProcessRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2173  		return k.client.WaitProcess(ctx, req.(*grpc.WaitProcessRequest), opts...)
  2174  	}
  2175  	k.reqHandlers[grpcTtyWinResizeRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2176  		return k.client.TtyWinResize(ctx, req.(*grpc.TtyWinResizeRequest), opts...)
  2177  	}
  2178  	k.reqHandlers[grpcWriteStreamRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2179  		return k.client.WriteStdin(ctx, req.(*grpc.WriteStreamRequest), opts...)
  2180  	}
  2181  	k.reqHandlers[grpcCloseStdinRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2182  		return k.client.CloseStdin(ctx, req.(*grpc.CloseStdinRequest), opts...)
  2183  	}
  2184  	k.reqHandlers[grpcStatsContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2185  		return k.client.StatsContainer(ctx, req.(*grpc.StatsContainerRequest), opts...)
  2186  	}
  2187  	k.reqHandlers[grpcPauseContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2188  		return k.client.PauseContainer(ctx, req.(*grpc.PauseContainerRequest), opts...)
  2189  	}
  2190  	k.reqHandlers[grpcResumeContainerRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2191  		return k.client.ResumeContainer(ctx, req.(*grpc.ResumeContainerRequest), opts...)
  2192  	}
  2193  	k.reqHandlers[grpcReseedRandomDevRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2194  		return k.client.ReseedRandomDev(ctx, req.(*grpc.ReseedRandomDevRequest), opts...)
  2195  	}
  2196  	k.reqHandlers[grpcGuestDetailsRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2197  		return k.client.GetGuestDetails(ctx, req.(*grpc.GuestDetailsRequest), opts...)
  2198  	}
  2199  	k.reqHandlers[grpcMemHotplugByProbeRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2200  		return k.client.MemHotplugByProbe(ctx, req.(*grpc.MemHotplugByProbeRequest), opts...)
  2201  	}
  2202  	k.reqHandlers[grpcCopyFileRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2203  		return k.client.CopyFile(ctx, req.(*grpc.CopyFileRequest), opts...)
  2204  	}
  2205  	k.reqHandlers[grpcSetGuestDateTimeRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2206  		return k.client.SetGuestDateTime(ctx, req.(*grpc.SetGuestDateTimeRequest), opts...)
  2207  	}
  2208  	k.reqHandlers[grpcStartTracingRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2209  		return k.client.StartTracing(ctx, req.(*grpc.StartTracingRequest), opts...)
  2210  	}
  2211  	k.reqHandlers[grpcStopTracingRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2212  		return k.client.StopTracing(ctx, req.(*grpc.StopTracingRequest), opts...)
  2213  	}
  2214  	k.reqHandlers[grpcGetOOMEventRequest] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
  2215  		return k.client.GetOOMEvent(ctx, req.(*grpc.GetOOMEventRequest), opts...)
  2216  	}
  2217  }
  2218  
  2219  func (k *kataAgent) getReqContext(reqName string) (ctx context.Context, cancel context.CancelFunc) {
  2220  	ctx = context.Background()
  2221  	switch reqName {
  2222  	case grpcWaitProcessRequest, grpcGetOOMEventRequest:
  2223  		// Wait and GetOOMEvent have no timeout
  2224  	case grpcCheckRequest:
  2225  		ctx, cancel = context.WithTimeout(ctx, checkRequestTimeout)
  2226  	default:
  2227  		ctx, cancel = context.WithTimeout(ctx, defaultRequestTimeout)
  2228  	}
  2229  
  2230  	return ctx, cancel
  2231  }
  2232  
  2233  func (k *kataAgent) sendReq(request interface{}) (interface{}, error) {
  2234  	span, _ := k.trace("sendReq")
  2235  	span.SetTag("request", request)
  2236  	defer span.Finish()
  2237  
  2238  	if err := k.connect(); err != nil {
  2239  		return nil, err
  2240  	}
  2241  	if !k.keepConn {
  2242  		defer k.disconnect()
  2243  	}
  2244  
  2245  	msgName := proto.MessageName(request.(proto.Message))
  2246  	handler := k.reqHandlers[msgName]
  2247  	if msgName == "" || handler == nil {
  2248  		return nil, errors.New("Invalid request type")
  2249  	}
  2250  	message := request.(proto.Message)
  2251  	ctx, cancel := k.getReqContext(msgName)
  2252  	if cancel != nil {
  2253  		defer cancel()
  2254  	}
  2255  	k.Logger().WithField("name", msgName).WithField("req", message.String()).Debug("sending request")
  2256  
  2257  	return handler(ctx, request)
  2258  }
  2259  
  2260  // readStdout and readStderr are special that we cannot differentiate them with the request types...
  2261  func (k *kataAgent) readProcessStdout(c *Container, processID string, data []byte) (int, error) {
  2262  	if err := k.connect(); err != nil {
  2263  		return 0, err
  2264  	}
  2265  	if !k.keepConn {
  2266  		defer k.disconnect()
  2267  	}
  2268  
  2269  	return k.readProcessStream(c.id, processID, data, k.client.ReadStdout)
  2270  }
  2271  
  2272  // readStdout and readStderr are special that we cannot differentiate them with the request types...
  2273  func (k *kataAgent) readProcessStderr(c *Container, processID string, data []byte) (int, error) {
  2274  	if err := k.connect(); err != nil {
  2275  		return 0, err
  2276  	}
  2277  	if !k.keepConn {
  2278  		defer k.disconnect()
  2279  	}
  2280  
  2281  	return k.readProcessStream(c.id, processID, data, k.client.ReadStderr)
  2282  }
  2283  
  2284  type readFn func(context.Context, *grpc.ReadStreamRequest, ...golangGrpc.CallOption) (*grpc.ReadStreamResponse, error)
  2285  
  2286  func (k *kataAgent) readProcessStream(containerID, processID string, data []byte, read readFn) (int, error) {
  2287  	resp, err := read(k.ctx, &grpc.ReadStreamRequest{
  2288  		ContainerId: containerID,
  2289  		ExecId:      processID,
  2290  		Len:         uint32(len(data))})
  2291  	if err == nil {
  2292  		copy(data, resp.Data)
  2293  		return len(resp.Data), nil
  2294  	}
  2295  
  2296  	return 0, err
  2297  }
  2298  
  2299  func (k *kataAgent) getGuestDetails(req *grpc.GuestDetailsRequest) (*grpc.GuestDetailsResponse, error) {
  2300  	resp, err := k.sendReq(req)
  2301  	if err != nil {
  2302  		return nil, err
  2303  	}
  2304  
  2305  	return resp.(*grpc.GuestDetailsResponse), nil
  2306  }
  2307  
  2308  func (k *kataAgent) setGuestDateTime(tv time.Time) error {
  2309  	_, err := k.sendReq(&grpc.SetGuestDateTimeRequest{
  2310  		Sec:  tv.Unix(),
  2311  		Usec: int64(tv.Nanosecond() / 1e3),
  2312  	})
  2313  
  2314  	return err
  2315  }
  2316  
  2317  func (k *kataAgent) convertToKataAgentIPFamily(ipFamily int) aTypes.IPFamily {
  2318  	switch ipFamily {
  2319  	case netlink.FAMILY_V4:
  2320  		return aTypes.IPFamily_v4
  2321  	case netlink.FAMILY_V6:
  2322  		return aTypes.IPFamily_v6
  2323  	}
  2324  
  2325  	return aTypes.IPFamily_v4
  2326  }
  2327  
  2328  func (k *kataAgent) convertToIPFamily(ipFamily aTypes.IPFamily) int {
  2329  	switch ipFamily {
  2330  	case aTypes.IPFamily_v4:
  2331  		return netlink.FAMILY_V4
  2332  	case aTypes.IPFamily_v6:
  2333  		return netlink.FAMILY_V6
  2334  	}
  2335  
  2336  	return netlink.FAMILY_V4
  2337  }
  2338  
  2339  func (k *kataAgent) convertToKataAgentIPAddress(ipAddr *vcTypes.IPAddress) (aIPAddr *aTypes.IPAddress) {
  2340  	if ipAddr == nil {
  2341  		return nil
  2342  	}
  2343  
  2344  	aIPAddr = &aTypes.IPAddress{
  2345  		Family:  k.convertToKataAgentIPFamily(ipAddr.Family),
  2346  		Address: ipAddr.Address,
  2347  		Mask:    ipAddr.Mask,
  2348  	}
  2349  
  2350  	return aIPAddr
  2351  }
  2352  
  2353  func (k *kataAgent) convertToKataAgentIPAddresses(ipAddrs []*vcTypes.IPAddress) (aIPAddrs []*aTypes.IPAddress) {
  2354  	for _, ipAddr := range ipAddrs {
  2355  		if ipAddr == nil {
  2356  			continue
  2357  		}
  2358  
  2359  		aIPAddr := k.convertToKataAgentIPAddress(ipAddr)
  2360  		aIPAddrs = append(aIPAddrs, aIPAddr)
  2361  	}
  2362  
  2363  	return aIPAddrs
  2364  }
  2365  
  2366  func (k *kataAgent) convertToIPAddresses(aIPAddrs []*aTypes.IPAddress) (ipAddrs []*vcTypes.IPAddress) {
  2367  	for _, aIPAddr := range aIPAddrs {
  2368  		if aIPAddr == nil {
  2369  			continue
  2370  		}
  2371  
  2372  		ipAddr := &vcTypes.IPAddress{
  2373  			Family:  k.convertToIPFamily(aIPAddr.Family),
  2374  			Address: aIPAddr.Address,
  2375  			Mask:    aIPAddr.Mask,
  2376  		}
  2377  
  2378  		ipAddrs = append(ipAddrs, ipAddr)
  2379  	}
  2380  
  2381  	return ipAddrs
  2382  }
  2383  
  2384  func (k *kataAgent) convertToKataAgentInterface(iface *vcTypes.Interface) *aTypes.Interface {
  2385  	if iface == nil {
  2386  		return nil
  2387  	}
  2388  
  2389  	return &aTypes.Interface{
  2390  		Device:      iface.Device,
  2391  		Name:        iface.Name,
  2392  		IPAddresses: k.convertToKataAgentIPAddresses(iface.IPAddresses),
  2393  		Mtu:         iface.Mtu,
  2394  		RawFlags:    iface.RawFlags,
  2395  		HwAddr:      iface.HwAddr,
  2396  		PciPath:     iface.PciPath.String(),
  2397  	}
  2398  }
  2399  
  2400  func (k *kataAgent) convertToInterfaces(aIfaces []*aTypes.Interface) ([]*vcTypes.Interface, error) {
  2401  	ifaces := make([]*vcTypes.Interface, 0)
  2402  	for _, aIface := range aIfaces {
  2403  		if aIface == nil {
  2404  			continue
  2405  		}
  2406  
  2407  		pcipath, err := vcTypes.PciPathFromString(aIface.PciPath)
  2408  		if err != nil {
  2409  			return nil, err
  2410  		}
  2411  		iface := &vcTypes.Interface{
  2412  			Device:      aIface.Device,
  2413  			Name:        aIface.Name,
  2414  			IPAddresses: k.convertToIPAddresses(aIface.IPAddresses),
  2415  			Mtu:         aIface.Mtu,
  2416  			HwAddr:      aIface.HwAddr,
  2417  			PciPath:     pcipath,
  2418  		}
  2419  
  2420  		ifaces = append(ifaces, iface)
  2421  	}
  2422  
  2423  	return ifaces, nil
  2424  }
  2425  
  2426  func (k *kataAgent) convertToKataAgentRoutes(routes []*vcTypes.Route) (aRoutes []*aTypes.Route) {
  2427  	for _, route := range routes {
  2428  		if route == nil {
  2429  			continue
  2430  		}
  2431  
  2432  		aRoute := &aTypes.Route{
  2433  			Dest:    route.Dest,
  2434  			Gateway: route.Gateway,
  2435  			Device:  route.Device,
  2436  			Source:  route.Source,
  2437  			Scope:   route.Scope,
  2438  		}
  2439  
  2440  		aRoutes = append(aRoutes, aRoute)
  2441  	}
  2442  
  2443  	return aRoutes
  2444  }
  2445  
  2446  func (k *kataAgent) convertToKataAgentNeighbors(neighs []*vcTypes.ARPNeighbor) (aNeighs []*aTypes.ARPNeighbor) {
  2447  	for _, neigh := range neighs {
  2448  		if neigh == nil {
  2449  			continue
  2450  		}
  2451  
  2452  		aNeigh := &aTypes.ARPNeighbor{
  2453  			ToIPAddress: k.convertToKataAgentIPAddress(neigh.ToIPAddress),
  2454  			Device:      neigh.Device,
  2455  			State:       int32(neigh.State),
  2456  			Lladdr:      neigh.LLAddr,
  2457  		}
  2458  
  2459  		aNeighs = append(aNeighs, aNeigh)
  2460  	}
  2461  
  2462  	return aNeighs
  2463  }
  2464  
  2465  func (k *kataAgent) convertToRoutes(aRoutes []*aTypes.Route) (routes []*vcTypes.Route) {
  2466  	for _, aRoute := range aRoutes {
  2467  		if aRoute == nil {
  2468  			continue
  2469  		}
  2470  
  2471  		route := &vcTypes.Route{
  2472  			Dest:    aRoute.Dest,
  2473  			Gateway: aRoute.Gateway,
  2474  			Device:  aRoute.Device,
  2475  			Source:  aRoute.Source,
  2476  			Scope:   aRoute.Scope,
  2477  		}
  2478  
  2479  		routes = append(routes, route)
  2480  	}
  2481  
  2482  	return routes
  2483  }
  2484  
  2485  func (k *kataAgent) copyFile(src, dst string) error {
  2486  	var st unix.Stat_t
  2487  
  2488  	err := unix.Stat(src, &st)
  2489  	if err != nil {
  2490  		return fmt.Errorf("Could not get file %s information: %v", src, err)
  2491  	}
  2492  
  2493  	b, err := ioutil.ReadFile(src)
  2494  	if err != nil {
  2495  		return fmt.Errorf("Could not read file %s: %v", src, err)
  2496  	}
  2497  
  2498  	fileSize := int64(len(b))
  2499  
  2500  	k.Logger().WithFields(logrus.Fields{
  2501  		"source": src,
  2502  		"dest":   dst,
  2503  	}).Debugf("Copying file from host to guest")
  2504  
  2505  	cpReq := &grpc.CopyFileRequest{
  2506  		Path:     dst,
  2507  		DirMode:  uint32(DirMode),
  2508  		FileMode: st.Mode,
  2509  		FileSize: fileSize,
  2510  		Uid:      int32(st.Uid),
  2511  		Gid:      int32(st.Gid),
  2512  	}
  2513  
  2514  	// Handle the special case where the file is empty
  2515  	if fileSize == 0 {
  2516  		_, err = k.sendReq(cpReq)
  2517  		return err
  2518  	}
  2519  
  2520  	// Copy file by parts if it's needed
  2521  	remainingBytes := fileSize
  2522  	offset := int64(0)
  2523  	for remainingBytes > 0 {
  2524  		bytesToCopy := int64(len(b))
  2525  		if bytesToCopy > grpcMaxDataSize {
  2526  			bytesToCopy = grpcMaxDataSize
  2527  		}
  2528  
  2529  		cpReq.Data = b[:bytesToCopy]
  2530  		cpReq.Offset = offset
  2531  
  2532  		if _, err = k.sendReq(cpReq); err != nil {
  2533  			return fmt.Errorf("Could not send CopyFile request: %v", err)
  2534  		}
  2535  
  2536  		b = b[bytesToCopy:]
  2537  		remainingBytes -= bytesToCopy
  2538  		offset += grpcMaxDataSize
  2539  	}
  2540  
  2541  	return nil
  2542  }
  2543  
  2544  func (k *kataAgent) markDead() {
  2545  	k.Logger().Infof("mark agent dead")
  2546  	k.dead = true
  2547  	k.disconnect()
  2548  }
  2549  
  2550  func (k *kataAgent) cleanup(s *Sandbox) {
  2551  	// Unmount shared path
  2552  	path := getSharePath(s.id)
  2553  	k.Logger().WithField("path", path).Infof("cleanup agent")
  2554  	if err := syscall.Unmount(path, syscall.MNT_DETACH|UmountNoFollow); err != nil {
  2555  		k.Logger().WithError(err).Errorf("failed to unmount vm share path %s", path)
  2556  	}
  2557  
  2558  	// Unmount mount path
  2559  	path = getMountPath(s.id)
  2560  	if err := bindUnmountAllRootfs(k.ctx, path, s); err != nil {
  2561  		k.Logger().WithError(err).Errorf("failed to unmount vm mount path %s", path)
  2562  	}
  2563  	if err := os.RemoveAll(getSandboxPath(s.id)); err != nil {
  2564  		k.Logger().WithError(err).Errorf("failed to cleanup vm path %s", getSandboxPath(s.id))
  2565  	}
  2566  }
  2567  
  2568  func (k *kataAgent) save() persistapi.AgentState {
  2569  	return persistapi.AgentState{
  2570  		ProxyPid: k.state.ProxyPid,
  2571  		URL:      k.state.URL,
  2572  	}
  2573  }
  2574  
  2575  func (k *kataAgent) load(s persistapi.AgentState) {
  2576  	k.state.ProxyPid = s.ProxyPid
  2577  	k.state.URL = s.URL
  2578  }
  2579  
  2580  func (k *kataAgent) getOOMEvent() (string, error) {
  2581  	req := &grpc.GetOOMEventRequest{}
  2582  	result, err := k.sendReq(req)
  2583  	if err != nil {
  2584  		return "", err
  2585  	}
  2586  	if oomEvent, ok := result.(*grpc.OOMEvent); ok {
  2587  		return oomEvent.ContainerId, nil
  2588  	}
  2589  	return "", err
  2590  }