diff --git a/virtcontainers/fc.go b/virtcontainers/fc.go index 461b6a480..96ac05829 100644 --- a/virtcontainers/fc.go +++ b/virtcontainers/fc.go @@ -7,34 +7,31 @@ package virtcontainers import ( "context" - "errors" "fmt" + "net" + "net/http" "net/url" "os/exec" "path/filepath" - "strconv" "strings" "sync" "syscall" "time" + "github.com/firecracker-microvm/firecracker-go-sdk/client" + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" + ops "github.com/firecracker-microvm/firecracker-go-sdk/client/operations" + httptransport "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" opentracing "github.com/opentracing/opentracing-go" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/store" "github.com/kata-containers/runtime/virtcontainers/types" - - "net" - "net/http" - - "github.com/go-openapi/strfmt" - - "github.com/firecracker-microvm/firecracker-go-sdk/client" - models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" - ops "github.com/firecracker-microvm/firecracker-go-sdk/client/operations" - httptransport "github.com/go-openapi/runtime/client" + "github.com/kata-containers/runtime/virtcontainers/utils" ) type vmmState uint8 @@ -694,16 +691,42 @@ func (fc *firecracker) resizeVCPUs(reqVCPUs uint32) (currentVCPUs uint32, newVCP return 0, 0, nil } -// this is used to apply cgroup information on the host. not sure how necessary this -// is in the first pass. +// This is used to apply cgroup information on the host. // -// Need to see if there's an easy way to ask firecracker for thread ids associated with -// the vCPUs. Issue opened to ask for per vCPU thread IDs: -// https://github.com/firecracker-microvm/firecracker/issues/718 +// As suggested by https://github.com/firecracker-microvm/firecracker/issues/718, +// let's use `ps -T -p ` to get fc vcpu info. func (fc *firecracker) getThreadIDs() (vcpuThreadIDs, error) { - //TODO: this may not be exactly supported in Firecracker. Closest is cpu-template as part - // of get /machine-config - return vcpuThreadIDs{}, nil + var vcpuInfo vcpuThreadIDs + + vcpuInfo.vcpus = make(map[int]int) + parent, err := utils.NewProc(fc.info.PID) + if err != nil { + return vcpuInfo, err + } + children, err := parent.Children() + if err != nil { + return vcpuInfo, err + } + for _, child := range children { + comm, err := child.Comm() + if err != nil { + return vcpuInfo, errors.New("Invalid fc thread info") + } + if !strings.HasPrefix(comm, "fc_vcpu") { + continue + } + cpus := strings.SplitAfter(comm, "fc_vcpu") + if len(cpus) != 2 { + return vcpuInfo, errors.Errorf("Invalid fc thread info: %v", comm) + } + cpuID, err := strconv.ParseInt(cpus[1], 10, 32) + if err != nil { + return vcpuInfo, errors.Wrapf(err, "Invalid fc thread info: %v", comm) + } + vcpuInfo.vcpus[int(cpuID)] = child.PID + } + + return vcpuInfo, nil } func (fc *firecracker) cleanup() error { diff --git a/virtcontainers/utils/proc_linux.go b/virtcontainers/utils/proc_linux.go new file mode 100644 index 000000000..93bd3e491 --- /dev/null +++ b/virtcontainers/utils/proc_linux.go @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Hyper.sh +// +// SPDX-License-Identifier: Apache-2.0 +// + +package utils + +import ( + "io/ioutil" + "path/filepath" + "strconv" + + "github.com/pkg/errors" + "github.com/prometheus/procfs" +) + +const taskPath = "task" + +type Proc struct { + *procfs.Proc +} + +func NewProc(pid int) (*Proc, error) { + p, err := procfs.NewProc(pid) + if err != nil { + return nil, errors.Wrapf(err, "Invalid pid %v", pid) + } + + return &Proc{&p}, nil +} + +// We should try to upstream this but let's keep it until upstream supports it. +func (p *Proc) Children() ([]*Proc, error) { + parent := strconv.Itoa(p.PID) + infos, err := ioutil.ReadDir(filepath.Join(procfs.DefaultMountPoint, parent, taskPath)) + if err != nil { + return nil, errors.Wrapf(err, "Fail to read pid %v proc task dir", p.PID) + } + + var children []*Proc + for _, info := range infos { + if !info.IsDir() || info.Name() == parent { + continue + } + pid, err := strconv.Atoi(info.Name()) + if err != nil { + return nil, errors.Wrapf(err, "Invalid child pid %v", info.Name()) + } + child, err := NewProc(pid) + if err != nil { + return nil, err + } + children = append(children, child) + } + + return children, nil +}