Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions pkg/pillar/cmd/domainmgr/domainmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1118,13 +1118,24 @@ func maybeRetryBoot(ctx *domainContext, status *types.DomainStatus) {
}
defer file.Close()

if err := hyper.Task(status).VirtualTPMSetup(status.DomainName, agentName, ctx.ps, warningTime, errorTime); err != nil {
log.Errorf("Failed to setup virtual TPM for %s: %s", status.DomainName, err)
status.VirtualTPM = false
} else {
status.VirtualTPM = true
}

if err := hyper.Task(status).Setup(*status, *config, ctx.assignableAdapters, nil, file); err != nil {
//it is retry, so omit error
log.Errorf("Failed to create DomainStatus from %+v: %s",
config, err)

if err := hyper.Task(status).VirtualTPMTerminate(status.DomainName); err != nil {
log.Errorf("Failed to terminate virtual TPM for %s: %s", status.DomainName, err)
}
}

status.TriedCount += 1
status.TriedCount++

ctx.createSema.V(1)
domainID, err := DomainCreate(ctx, *status)
Expand Down Expand Up @@ -1659,20 +1670,32 @@ func doActivate(ctx *domainContext, config types.DomainConfig,
}
defer file.Close()

if err := hyper.Task(status).VirtualTPMSetup(status.DomainName, agentName, ctx.ps, warningTime, errorTime); err != nil {
log.Errorf("Failed to setup virtual TPM for %s: %s", status.DomainName, err)
status.VirtualTPM = false
} else {
status.VirtualTPM = true
}

globalConfig := agentlog.GetGlobalConfig(log, ctx.subGlobalConfig)
if err := hyper.Task(status).Setup(*status, config, ctx.assignableAdapters, globalConfig, file); err != nil {
log.Errorf("Failed to create DomainStatus from %+v: %s",
config, err)
status.SetErrorNow(err.Error())
releaseCPUs(ctx, &config, status)

if err := hyper.Task(status).VirtualTPMTerminate(status.DomainName); err != nil {
log.Errorf("Failed to terminate virtual TPM for %s: %s", status.DomainName, err)
}

return
}

status.TriedCount = 0
var domainID int
// Invoke domain create; try 3 times with a timeout
for {
status.TriedCount += 1
status.TriedCount++
var err error
ctx.createSema.V(1)
domainID, err = DomainCreate(ctx, *status)
Expand Down Expand Up @@ -2424,6 +2447,10 @@ func handleDelete(ctx *domainContext, key string, status *types.DomainStatus) {
log.Errorln(err)
}

if err := hyper.Task(status).VirtualTPMTeardown(status.DomainName); err != nil {
log.Errorln(err)
}

log.Functionf("handleDelete(%v) DONE for %s",
status.UUIDandVersion, status.DisplayName)
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/pillar/hypervisor/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/lf-edge/eve/pkg/pillar/containerd"
"github.com/lf-edge/eve/pkg/pillar/pubsub"
"github.com/lf-edge/eve/pkg/pillar/types"
"github.com/opencontainers/runtime-spec/specs-go"

Expand Down Expand Up @@ -314,3 +315,15 @@ func (ctx ctrdContext) GetDomsCPUMem() (map[string]types.DomainMetric, error) {
}
return res, nil
}

func (ctx ctrdContext) VirtualTPMSetup(domainName, agentName string, ps *pubsub.PubSub, warnTime, errTime time.Duration) error {
return fmt.Errorf("not implemented")
}

func (ctx ctrdContext) VirtualTPMTerminate(domainName string) error {
return fmt.Errorf("not implemented")
}

func (ctx ctrdContext) VirtualTPMTeardown(domainName string) error {
return fmt.Errorf("not implemented")
}
51 changes: 0 additions & 51 deletions pkg/pillar/hypervisor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ package hypervisor

import (
"fmt"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/lf-edge/eve/pkg/pillar/base"
"github.com/lf-edge/eve/pkg/pillar/types"
Expand Down Expand Up @@ -243,51 +240,3 @@ func PCISameControllerGeneric(id1 string, id2 string) bool {

return tag1 == tag2
}

func launchSwtpm(id string, timeoutSeconds uint) (string, error) {
conn, err := net.Dial("unix", types.VtpmdCtrlSocket)
if err != nil {
return "", fmt.Errorf("failed to connect to vtpmd control socket: %w", err)
}
defer conn.Close()

pidPath := fmt.Sprintf(types.SwtpmPidPath, id)
sockPath := fmt.Sprintf(types.SwtpmCtrlSocketPath, id)

// Send the id to the swtpm control socket,ask it to launch swtpm instance.
_, err = conn.Write([]byte(fmt.Sprintf("%s\n", id)))
if err != nil {
return "", fmt.Errorf("failed to write to vtpmd control socket: %w", err)
}

// loop and wait for swtpm to launch
startTime := time.Now()
for {
if time.Since(startTime).Seconds() >= float64(timeoutSeconds) {
return "", fmt.Errorf("timeout reached while waiting for swtpm to launch")
}

// check if swtpm is running by checking the pid file
if fileutils.FileExists(nil, pidPath) {
break
}

time.Sleep(1 * time.Second)
}

// read the pid file and make sure the process is running
content, err := os.ReadFile(pidPath)
if err != nil {
return "", fmt.Errorf("failed to read swtpm pid file: %w", err)
}
pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
if err != nil {
return "", fmt.Errorf("failed to parse swtpm pid: %w", err)
}
_, err = os.FindProcess(pid)
if err != nil {
return "", fmt.Errorf("swtpm process not found: %w", err)
}

return sockPath, nil
}
13 changes: 13 additions & 0 deletions pkg/pillar/hypervisor/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/lf-edge/eve/pkg/pillar/base"
"github.com/lf-edge/eve/pkg/pillar/pubsub"
"github.com/lf-edge/eve/pkg/pillar/types"

netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
Expand Down Expand Up @@ -1360,3 +1361,15 @@ func (ctx kubevirtContext) PCIRelease(long string) error {
func (ctx kubevirtContext) PCISameController(id1 string, id2 string) bool {
return PCISameControllerGeneric(id1, id2)
}

func (ctx kubevirtContext) VirtualTPMSetup(domainName, agentName string, ps *pubsub.PubSub, warnTime, errTime time.Duration) error {
return fmt.Errorf("not implemented")
}

func (ctx kubevirtContext) VirtualTPMTerminate(domainName string) error {
return fmt.Errorf("not implemented")
}

func (ctx kubevirtContext) VirtualTPMTeardown(domainName string) error {
return fmt.Errorf("not implemented")
}
115 changes: 106 additions & 9 deletions pkg/pillar/hypervisor/kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package hypervisor

import (
"fmt"
"net"
"os"
"path/filepath"
"runtime"
Expand All @@ -16,16 +17,24 @@ import (
zconfig "github.com/lf-edge/eve-api/go/config"
"github.com/lf-edge/eve/pkg/pillar/agentlog"
"github.com/lf-edge/eve/pkg/pillar/containerd"
"github.com/lf-edge/eve/pkg/pillar/pubsub"
"github.com/lf-edge/eve/pkg/pillar/types"
"github.com/lf-edge/eve/pkg/pillar/utils"
uuid "github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

// KVMHypervisorName is a name of kvm hypervisor
const KVMHypervisorName = "kvm"
const minUringKernelTag = uint64((5 << 16) | (4 << 8) | (72 << 0))
const swtpmTimeout = 10 // seconds
const (
// KVMHypervisorName is a name of kvm hypervisor
KVMHypervisorName = "kvm"
minUringKernelTag = uint64((5 << 16) | (4 << 8) | (72 << 0))
swtpmTimeout = 10 // seconds
qemuTimeout = 3 // seconds
vtpmPurgePrefix = "purge;"
vtpmdeletePrefix = "terminate;"
vtpmlaunchPrefix = "launch;"
)

var clientCid = uint32(unix.VMADDR_CID_HOST + 1)

Expand Down Expand Up @@ -699,11 +708,10 @@ func (ctx KvmContext) Setup(status types.DomainStatus, config types.DomainConfig
domainName := status.DomainName
domainUUID := status.UUIDandVersion.UUID

swtpmCtrlSock, err := launchSwtpm(domainUUID.String(), swtpmTimeout)
if err != nil {
// let the vm start without TPM
logError("failed to launch swtpm for domain %s: %v", domainName, err)
swtpmCtrlSock = ""
// check if vTPM is enabled
swtpmCtrlSock := ""
if status.VirtualTPM {
swtpmCtrlSock = fmt.Sprintf(types.SwtpmCtrlSocketPath, domainName)
}

// first lets build the domain config
Expand Down Expand Up @@ -1168,3 +1176,92 @@ func GetQmpExecutorSocket(domainName string) string {
func getQmpListenerSocket(domainName string) string {
return filepath.Join(kvmStateDir, domainName, "listener.qmp")
}

// VirtualTPMSetup launches a vTPM instance for the domain
func (ctx KvmContext) VirtualTPMSetup(domainName, agentName string, ps *pubsub.PubSub, warnTime, errTime time.Duration) error {
if ps != nil {
wk := utils.NewWatchdogKick(ps, agentName, warnTime, errTime)
return requestVtpmLaunch(domainName, wk, swtpmTimeout)
}

return fmt.Errorf("invalid watchdog configuration")
}

// VirtualTPMTerminate terminates the vTPM instance
func (ctx KvmContext) VirtualTPMTerminate(domainName string) error {
if err := requestVtpmTermination(domainName); err != nil {
return fmt.Errorf("failed to terminate vTPM for domain %s: %w", domainName, err)
}
return nil
}

// VirtualTPMTeardown purges the vTPM instance.
func (ctx KvmContext) VirtualTPMTeardown(domainName string) error {
if err := requestVtpmPurge(domainName); err != nil {
return fmt.Errorf("failed to purge vTPM for domain %s: %w", domainName, err)
}

return nil
}

func requestVtpmLaunch(id string, wk *utils.WatchdogKick, timeoutSeconds uint) error {
conn, err := net.Dial("unix", types.VtpmdCtrlSocket)
if err != nil {
return fmt.Errorf("failed to connect to vtpmd control socket: %w", err)
}
defer conn.Close()

pidPath := fmt.Sprintf(types.SwtpmPidPath, id)

// Send the request to the vTPM control socket, ask it to launch a swtpm instance.
_, err = conn.Write([]byte(fmt.Sprintf("%s%s\n", vtpmlaunchPrefix, id)))
if err != nil {
return fmt.Errorf("failed to write to vtpmd control socket: %w", err)
}

// Loop and wait for SWTPM to start.
pid, err := utils.GetPidFromFileTimeout(pidPath, timeoutSeconds, wk)
if err != nil {
return fmt.Errorf("failed to get pid from file %s: %w", pidPath, err)
}

// One last time, check SWTPM is not dead right after launch.
if !utils.IsProcAlive(pid) {
return fmt.Errorf("SWTPM (pid: %d) is dead", pid)
}

return nil
}

func requestVtpmPurge(id string) error {
conn, err := net.Dial("unix", types.VtpmdCtrlSocket)
if err != nil {
return fmt.Errorf("failed to connect to vtpmd control socket: %w", err)
}
defer conn.Close()

// Send a request to vTPM control socket, ask it to purge the instance
// and all its data.
_, err = conn.Write([]byte(fmt.Sprintf("%s%s\n", vtpmPurgePrefix, id)))
if err != nil {
return fmt.Errorf("failed to write to vtpmd control socket: %w", err)
}

return nil
}

func requestVtpmTermination(id string) error {
conn, err := net.Dial("unix", types.VtpmdCtrlSocket)
if err != nil {
return fmt.Errorf("failed to connect to vtpmd control socket: %w", err)
}
defer conn.Close()

// Send a request to the vTPM control socket, ask it to delete the instance.
_, err = conn.Write([]byte(fmt.Sprintf("%s%s\n", vtpmdeletePrefix, id)))
if err != nil {
return fmt.Errorf("failed to write to vtpmd control socket: %w", err)
}

return nil
}
17 changes: 16 additions & 1 deletion pkg/pillar/hypervisor/null.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ package hypervisor

import (
"fmt"
"github.com/lf-edge/eve/pkg/pillar/types"
"os"
"time"

"github.com/lf-edge/eve/pkg/pillar/pubsub"
"github.com/lf-edge/eve/pkg/pillar/types"

uuid "github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -170,3 +173,15 @@ func (ctx nullContext) GetHostCPUMem() (types.HostMemory, error) {
func (ctx nullContext) GetDomsCPUMem() (map[string]types.DomainMetric, error) {
return nil, nil
}

func (ctx nullContext) VirtualTPMSetup(domainName, agentName string, ps *pubsub.PubSub, warnTime, errTime time.Duration) error {
return fmt.Errorf("not implemented")
}

func (ctx nullContext) VirtualTPMTerminate(domainName string) error {
return fmt.Errorf("not implemented")
}

func (ctx nullContext) VirtualTPMTeardown(domainName string) error {
return fmt.Errorf("not implemented")
}
14 changes: 14 additions & 0 deletions pkg/pillar/hypervisor/xen.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"runtime"
"strconv"
"strings"
"time"

"github.com/lf-edge/eve/pkg/pillar/pubsub"
"github.com/lf-edge/eve/pkg/pillar/types"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/mem"
Expand Down Expand Up @@ -873,3 +875,15 @@ func fallbackDomainMetric() map[string]types.DomainMetric {
dmList[dom0Name] = dm
return dmList
}

func (ctx xenContext) VirtualTPMSetup(domainName, agentName string, ps *pubsub.PubSub, warnTime, errTime time.Duration) error {
return fmt.Errorf("not implemented")
}

func (ctx xenContext) VirtualTPMTerminate(domainName string) error {
return fmt.Errorf("not implemented")
}

func (ctx xenContext) VirtualTPMTeardown(domainName string) error {
return fmt.Errorf("not implemented")
}
Loading