mirror of
https://github.com/containers/gvisor-tap-vsock.git
synced 2025-12-24 13:29:22 +08:00
Add Qemu support
User can now choose between vpnkit or qemu protocol. Qemu needs to be run with this argument: `-netdev socket,id=vlan,connect=IP:PORT -device virtio-net-pci,netdev=vlan` where IP and PORT represent the daemon on the host. This extra port allocation can be avoided with the qemu-wrapper in cmd/. The daemon can listen a unix domain socket, the wrapper will pass it to Qemu as a file descriptor.
This commit is contained in:
@@ -22,6 +22,7 @@ var (
|
||||
mtu int
|
||||
endpoints arrayFlags
|
||||
vpnkitSocket string
|
||||
qemuSocket string
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -29,6 +30,7 @@ func main() {
|
||||
flag.BoolVar(&debug, "debug", false, "debug")
|
||||
flag.IntVar(&mtu, "mtu", 1500, "mtu")
|
||||
flag.StringVar(&vpnkitSocket, "listen-vpnkit", "", "VPNKit socket to be used by Hyperkit")
|
||||
flag.StringVar(&qemuSocket, "listen-qemu", "", "Socket to be used by Qemu")
|
||||
flag.Parse()
|
||||
|
||||
if debug {
|
||||
@@ -39,6 +41,15 @@ func main() {
|
||||
endpoints = append(endpoints, transport.DefaultURL)
|
||||
}
|
||||
|
||||
if vpnkitSocket != "" && qemuSocket != "" {
|
||||
log.Fatal("cannot use qemu and vpnkit protocol at the same time")
|
||||
}
|
||||
|
||||
protocol := types.HyperKitProtocol
|
||||
if qemuSocket != "" {
|
||||
protocol = types.QemuProtocol
|
||||
}
|
||||
|
||||
if err := run(&types.Configuration{
|
||||
Debug: debug,
|
||||
CaptureFile: captureFile(),
|
||||
@@ -89,6 +100,7 @@ func main() {
|
||||
VpnKitUUIDMacAddresses: map[string]string{
|
||||
"c3d68012-0208-11ea-9fd7-f2189899ab08": "5a:94:ef:e4:0c:ee",
|
||||
},
|
||||
Protocol: protocol,
|
||||
}, endpoints); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -162,6 +174,27 @@ func run(configuration *types.Configuration, endpoints []string) error {
|
||||
}()
|
||||
}
|
||||
|
||||
if qemuSocket != "" {
|
||||
qemuListener, err := transport.Listen(qemuSocket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
conn, err := qemuListener.Accept()
|
||||
if err != nil {
|
||||
log.Errorf("qemu accept error: %s", err)
|
||||
continue
|
||||
}
|
||||
go func() {
|
||||
if err := vn.AcceptQemu(conn); err != nil {
|
||||
log.Errorf("qemu error: %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
ln, err := vn.Listen("tcp", fmt.Sprintf("%s:8080", configuration.GatewayIP))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
6
cmd/qemu-wrapper/README.md
Normal file
6
cmd/qemu-wrapper/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Qemu doesn't accept a unix socket as netdev, only a file descriptro.
|
||||
This wrapper is filling the gap.
|
||||
|
||||
```
|
||||
$ ./qemu-wrapper /tmp/qemu.sock qemu-system-x86_64 [...] -netdev socket,id=vlan,fd=3 -device virtio-net-pci,netdev=vlan
|
||||
```
|
||||
27
cmd/qemu-wrapper/main.go
Normal file
27
cmd/qemu-wrapper/main.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := net.Dial("unix", os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fd, err := conn.(*net.UnixConn).File()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(os.Args[2], os.Args[3:]...)
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, fd)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
39
pkg/tap/protocol.go
Normal file
39
pkg/tap/protocol.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package tap
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
type protocol interface {
|
||||
Buf() []byte
|
||||
Write(buf []byte, size int)
|
||||
Read(buf []byte) int
|
||||
}
|
||||
|
||||
type hyperkitProtocol struct {
|
||||
}
|
||||
|
||||
func (s *hyperkitProtocol) Buf() []byte {
|
||||
return make([]byte, 2)
|
||||
}
|
||||
|
||||
func (s *hyperkitProtocol) Write(buf []byte, size int) {
|
||||
binary.LittleEndian.PutUint16(buf, uint16(size))
|
||||
}
|
||||
|
||||
func (s *hyperkitProtocol) Read(buf []byte) int {
|
||||
return int(binary.LittleEndian.Uint16(buf[0:2]))
|
||||
}
|
||||
|
||||
type qemuProtocol struct {
|
||||
}
|
||||
|
||||
func (s *qemuProtocol) Buf() []byte {
|
||||
return make([]byte, 4)
|
||||
}
|
||||
|
||||
func (s *qemuProtocol) Write(buf []byte, size int) {
|
||||
binary.BigEndian.PutUint32(buf, uint32(size))
|
||||
}
|
||||
|
||||
func (s *qemuProtocol) Read(buf []byte) int {
|
||||
return int(binary.BigEndian.Uint32(buf[0:4]))
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package tap
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/code-ready/gvisor-tap-vsock/pkg/types"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/pkg/errors"
|
||||
@@ -45,14 +45,17 @@ type Switch struct {
|
||||
writeLock sync.Mutex
|
||||
|
||||
gateway VirtualDevice
|
||||
|
||||
protocol protocol
|
||||
}
|
||||
|
||||
func NewSwitch(debug bool, mtu int) *Switch {
|
||||
func NewSwitch(debug bool, mtu int, protocol types.Protocol) *Switch {
|
||||
return &Switch{
|
||||
debug: debug,
|
||||
maxTransmissionUnit: mtu,
|
||||
conns: make(map[int]net.Conn),
|
||||
cam: make(map[tcpip.LinkAddress]int),
|
||||
protocol: protocolImplementation(protocol),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +111,8 @@ func (e *Switch) connect(conn net.Conn) (int, bool) {
|
||||
}
|
||||
|
||||
func (e *Switch) tx(src, dst tcpip.LinkAddress, pkt *stack.PacketBuffer) error {
|
||||
size := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(size, uint16(pkt.Size()))
|
||||
size := e.protocol.Buf()
|
||||
e.protocol.Write(size, pkt.Size())
|
||||
|
||||
e.writeLock.Lock()
|
||||
defer e.writeLock.Unlock()
|
||||
@@ -179,17 +182,14 @@ func (e *Switch) disconnect(id int, conn net.Conn) {
|
||||
}
|
||||
|
||||
func (e *Switch) rx(id int, conn net.Conn) error {
|
||||
sizeBuf := make([]byte, 2)
|
||||
sizeBuf := e.protocol.Buf()
|
||||
|
||||
for {
|
||||
n, err := io.ReadFull(conn, sizeBuf)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot read size from socket")
|
||||
}
|
||||
if n != 2 {
|
||||
return fmt.Errorf("unexpected size %d", n)
|
||||
}
|
||||
size := int(binary.LittleEndian.Uint16(sizeBuf[0:2]))
|
||||
size := int(e.protocol.Read(sizeBuf))
|
||||
|
||||
buf := make([]byte, size)
|
||||
n, err = io.ReadFull(conn, buf)
|
||||
@@ -235,3 +235,10 @@ func (e *Switch) rx(id int, conn net.Conn) error {
|
||||
atomic.AddUint64(&e.Received, uint64(size))
|
||||
}
|
||||
}
|
||||
|
||||
func protocolImplementation(protocol types.Protocol) protocol {
|
||||
if protocol == types.QemuProtocol {
|
||||
return &qemuProtocol{}
|
||||
}
|
||||
return &hyperkitProtocol{}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,17 @@ type Configuration struct {
|
||||
DHCPStaticLeases map[string]string
|
||||
|
||||
VpnKitUUIDMacAddresses map[string]string
|
||||
|
||||
Protocol Protocol
|
||||
}
|
||||
|
||||
type Protocol string
|
||||
|
||||
const (
|
||||
HyperKitProtocol Protocol = "hyperkit"
|
||||
QemuProtocol Protocol = "qemu"
|
||||
)
|
||||
|
||||
type Zone struct {
|
||||
Name string
|
||||
Records []Record
|
||||
|
||||
10
pkg/virtualnetwork/qemu.go
Normal file
10
pkg/virtualnetwork/qemu.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package virtualnetwork
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (n *VirtualNetwork) AcceptQemu(conn net.Conn) error {
|
||||
n.networkSwitch.Accept(conn)
|
||||
return nil
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func New(configuration *types.Configuration) (*VirtualNetwork, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create tap endpoint")
|
||||
}
|
||||
networkSwitch := tap.NewSwitch(configuration.Debug, configuration.MTU)
|
||||
networkSwitch := tap.NewSwitch(configuration.Debug, configuration.MTU, configuration.Protocol)
|
||||
tapEndpoint.Connect(networkSwitch)
|
||||
networkSwitch.Connect(tapEndpoint)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user