1
0
mirror of https://github.com/kata-containers/kata-containers.git synced 2025-04-29 12:14:48 +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:
Julio Montes 2018-07-30 15:07:11 -05:00
parent 84b212f1b8
commit 03f1a1c3a8
2 changed files with 42 additions and 4 deletions

View File

@ -24,6 +24,8 @@ import (
"fmt"
"io"
"net"
"os"
"syscall"
"time"
"context"
@ -118,6 +120,7 @@ type qmpCommand struct {
args map[string]interface{}
filter *qmpEventFilter
resultReceived bool
oob []byte
}
// 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))
encodedCmd = append(encodedCmd, '\n')
_, err = q.conn.Write(encodedCmd)
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)
}
if err != nil {
cmd.res <- qmpResult{
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{},
filter *qmpEventFilter) (interface{}, error) {
oob []byte, filter *qmpEventFilter) (interface{}, error) {
var err error
var response interface{}
resCh := make(chan qmpResult)
@ -498,6 +506,7 @@ func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args
name: name,
args: args,
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{},
filter *qmpEventFilter) error {
_, err := q.executeCommandWithResponse(ctx, name, args, filter)
_, err := q.executeCommandWithResponse(ctx, name, args, nil, filter)
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
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 {
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)
}
// 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
}

View File

@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"log"
"os"
"reflect"
"sync"
"testing"
@ -962,3 +963,20 @@ func TestExecutePCIVSockAdd(t *testing.T) {
q.Shutdown()
<-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
}