mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-05-01 05:04:26 +00:00
qemu/qmp: implement getfd
`getfd` receives a file descriptor via SCM rights and assign it a name, this command is useful to send file descriptors from the host, and then hot plug devices that needs file descriptors like vhost-vsock-pci devices. Signed-off-by: Julio Montes <julio.montes@intel.com>
This commit is contained in:
parent
84b212f1b8
commit
03f1a1c3a8
26
qemu/qmp.go
26
qemu/qmp.go
@ -24,6 +24,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
@ -118,6 +120,7 @@ type qmpCommand struct {
|
|||||||
args map[string]interface{}
|
args map[string]interface{}
|
||||||
filter *qmpEventFilter
|
filter *qmpEventFilter
|
||||||
resultReceived bool
|
resultReceived bool
|
||||||
|
oob []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// QMP is a structure that contains the internal state used by startQMPLoop and
|
// QMP is a structure that contains the internal state used by startQMPLoop and
|
||||||
@ -302,7 +305,12 @@ func (q *QMP) writeNextQMPCommand(cmdQueue *list.List) {
|
|||||||
}
|
}
|
||||||
q.cfg.Logger.Infof("%s", string(encodedCmd))
|
q.cfg.Logger.Infof("%s", string(encodedCmd))
|
||||||
encodedCmd = append(encodedCmd, '\n')
|
encodedCmd = append(encodedCmd, '\n')
|
||||||
|
if unixConn, ok := q.conn.(*net.UnixConn); ok && len(cmd.oob) > 0 {
|
||||||
|
_, _, err = unixConn.WriteMsgUnix(encodedCmd, cmd.oob, nil)
|
||||||
|
} else {
|
||||||
_, err = q.conn.Write(encodedCmd)
|
_, err = q.conn.Write(encodedCmd)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.res <- qmpResult{
|
cmd.res <- qmpResult{
|
||||||
err: fmt.Errorf("Unable to write command to qmp socket %v", err),
|
err: fmt.Errorf("Unable to write command to qmp socket %v", err),
|
||||||
@ -485,7 +493,7 @@ func startQMPLoop(conn io.ReadWriteCloser, cfg QMPConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args map[string]interface{},
|
func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args map[string]interface{},
|
||||||
filter *qmpEventFilter) (interface{}, error) {
|
oob []byte, filter *qmpEventFilter) (interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
var response interface{}
|
var response interface{}
|
||||||
resCh := make(chan qmpResult)
|
resCh := make(chan qmpResult)
|
||||||
@ -498,6 +506,7 @@ func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args
|
|||||||
name: name,
|
name: name,
|
||||||
args: args,
|
args: args,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
|
oob: oob,
|
||||||
}:
|
}:
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,7 +528,7 @@ func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args
|
|||||||
func (q *QMP) executeCommand(ctx context.Context, name string, args map[string]interface{},
|
func (q *QMP) executeCommand(ctx context.Context, name string, args map[string]interface{},
|
||||||
filter *qmpEventFilter) error {
|
filter *qmpEventFilter) error {
|
||||||
|
|
||||||
_, err := q.executeCommandWithResponse(ctx, name, args, filter)
|
_, err := q.executeCommandWithResponse(ctx, name, args, nil, filter)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +818,7 @@ func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID,
|
|||||||
|
|
||||||
// ExecuteQueryHotpluggableCPUs returns a slice with the list of hotpluggable CPUs
|
// ExecuteQueryHotpluggableCPUs returns a slice with the list of hotpluggable CPUs
|
||||||
func (q *QMP) ExecuteQueryHotpluggableCPUs(ctx context.Context) ([]HotpluggableCPU, error) {
|
func (q *QMP) ExecuteQueryHotpluggableCPUs(ctx context.Context) ([]HotpluggableCPU, error) {
|
||||||
response, err := q.executeCommandWithResponse(ctx, "query-hotpluggable-cpus", nil, nil)
|
response, err := q.executeCommandWithResponse(ctx, "query-hotpluggable-cpus", nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -897,3 +906,14 @@ func (q *QMP) ExecutePCIVSockAdd(ctx context.Context, id, guestCID, vhostfd stri
|
|||||||
|
|
||||||
return q.executeCommand(ctx, "device_add", args, nil)
|
return q.executeCommand(ctx, "device_add", args, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecuteGetFD sends a file descriptor via SCM rights and assigns it a name
|
||||||
|
func (q *QMP) ExecuteGetFD(ctx context.Context, fdname string, fd *os.File) error {
|
||||||
|
oob := syscall.UnixRights(int(fd.Fd()))
|
||||||
|
args := map[string]interface{}{
|
||||||
|
"fdname": fdname,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := q.executeCommandWithResponse(ctx, "getfd", args, oob, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@ -962,3 +963,20 @@ func TestExecutePCIVSockAdd(t *testing.T) {
|
|||||||
q.Shutdown()
|
q.Shutdown()
|
||||||
<-disconnectedCh
|
<-disconnectedCh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks getfd
|
||||||
|
func TestExecuteGetFdD(t *testing.T) {
|
||||||
|
connectedCh := make(chan *QMPVersion)
|
||||||
|
disconnectedCh := make(chan struct{})
|
||||||
|
buf := newQMPTestCommandBuffer(t)
|
||||||
|
buf.AddCommand("getfd", nil, "return", nil)
|
||||||
|
cfg := QMPConfig{Logger: qmpTestLogger{}}
|
||||||
|
q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh)
|
||||||
|
checkVersion(t, connectedCh)
|
||||||
|
err := q.ExecuteGetFD(context.Background(), "foo", os.NewFile(0, "foo"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error %v", err)
|
||||||
|
}
|
||||||
|
q.Shutdown()
|
||||||
|
<-disconnectedCh
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user