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