Port netstack, hostinet, and netlink sockets to VFS2.

All three follow the same pattern:
1. Refactor VFS1 sockets into socketOpsCommon, so that most of the methods can
   be shared with VFS2.
2. Create a FileDescriptionImpl with the corresponding socket operations,
   rewriting the few that cannot be shared with VFS1.
3. Set up a VFS2 socket provider that creates a socket by setting up a dentry
   in the global Kernel.socketMount and connecting it with a new
   FileDescription.

This mostly completes the work for porting sockets to VFS2, and many syscall
tests can be enabled as a result.
There are several networking-related syscall tests that are still not passing:
1. net gofer tests
2. socketpair gofer tests
2. sendfile tests (splice is not implemented in VFS2 yet)

Updates #1478, #1484, #1485

PiperOrigin-RevId: 309457331
This commit is contained in:
Dean Deng
2020-05-01 12:54:41 -07:00
committed by gVisor bot
parent 8962b7840f
commit 82bae30cee
19 changed files with 1090 additions and 126 deletions
+1 -1
View File
@@ -411,7 +411,7 @@ func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount) (*vfs.F
return nil, syserror.ENOTTY
}
ep, err := newEndpoint(ctx, i.hostFD)
ep, err := newEndpoint(ctx, i.hostFD, &i.queue)
if err != nil {
return nil, err
}
+25 -28
View File
@@ -34,17 +34,16 @@ import (
"gvisor.dev/gvisor/pkg/waiter"
)
// Create a new host-backed endpoint from the given fd.
func newEndpoint(ctx context.Context, hostFD int) (transport.Endpoint, error) {
// Create a new host-backed endpoint from the given fd and its corresponding
// notification queue.
func newEndpoint(ctx context.Context, hostFD int, queue *waiter.Queue) (transport.Endpoint, error) {
// Set up an external transport.Endpoint using the host fd.
addr := fmt.Sprintf("hostfd:[%d]", hostFD)
var q waiter.Queue
e, err := NewConnectedEndpoint(ctx, hostFD, &q, addr, true /* saveable */)
e, err := NewConnectedEndpoint(ctx, hostFD, addr, true /* saveable */)
if err != nil {
return nil, err.ToError()
}
e.Init()
ep := transport.NewExternal(ctx, e.stype, uniqueid.GlobalProviderFromContext(ctx), &q, e, e)
ep := transport.NewExternal(ctx, e.stype, uniqueid.GlobalProviderFromContext(ctx), queue, e, e)
return ep, nil
}
@@ -77,8 +76,6 @@ type ConnectedEndpoint struct {
// addr is the address at which this endpoint is bound.
addr string
queue *waiter.Queue
// sndbuf is the size of the send buffer.
//
// N.B. When this is smaller than the host size, we present it via
@@ -134,11 +131,10 @@ func (c *ConnectedEndpoint) init() *syserr.Error {
// The caller is responsible for calling Init(). Additionaly, Release needs to
// be called twice because ConnectedEndpoint is both a transport.Receiver and
// transport.ConnectedEndpoint.
func NewConnectedEndpoint(ctx context.Context, hostFD int, queue *waiter.Queue, addr string, saveable bool) (*ConnectedEndpoint, *syserr.Error) {
func NewConnectedEndpoint(ctx context.Context, hostFD int, addr string, saveable bool) (*ConnectedEndpoint, *syserr.Error) {
e := ConnectedEndpoint{
fd: hostFD,
addr: addr,
queue: queue,
fd: hostFD,
addr: addr,
}
if err := e.init(); err != nil {
@@ -151,13 +147,6 @@ func NewConnectedEndpoint(ctx context.Context, hostFD int, queue *waiter.Queue,
return &e, nil
}
// Init will do the initialization required without holding other locks.
func (c *ConnectedEndpoint) Init() {
if err := fdnotifier.AddFD(int32(c.fd), c.queue); err != nil {
panic(err)
}
}
// Send implements transport.ConnectedEndpoint.Send.
func (c *ConnectedEndpoint) Send(data [][]byte, controlMessages transport.ControlMessages, from tcpip.FullAddress) (int64, bool, *syserr.Error) {
c.mu.RLock()
@@ -332,7 +321,6 @@ func (c *ConnectedEndpoint) RecvMaxQueueSize() int64 {
}
func (c *ConnectedEndpoint) destroyLocked() {
fdnotifier.RemoveFD(int32(c.fd))
c.fd = -1
}
@@ -350,14 +338,20 @@ func (c *ConnectedEndpoint) Release() {
func (c *ConnectedEndpoint) CloseUnread() {}
// SCMConnectedEndpoint represents an endpoint backed by a host fd that was
// passed through a gofer Unix socket. It is almost the same as
// ConnectedEndpoint, with the following differences:
// passed through a gofer Unix socket. It resembles ConnectedEndpoint, with the
// following differences:
// - SCMConnectedEndpoint is not saveable, because the host cannot guarantee
// the same descriptor number across S/R.
// - SCMConnectedEndpoint holds ownership of its fd and is responsible for
// closing it.
// - SCMConnectedEndpoint holds ownership of its fd and notification queue.
type SCMConnectedEndpoint struct {
ConnectedEndpoint
queue *waiter.Queue
}
// Init will do the initialization required without holding other locks.
func (e *SCMConnectedEndpoint) Init() error {
return fdnotifier.AddFD(int32(e.fd), e.queue)
}
// Release implements transport.ConnectedEndpoint.Release and
@@ -368,6 +362,7 @@ func (e *SCMConnectedEndpoint) Release() {
if err := syscall.Close(e.fd); err != nil {
log.Warningf("Failed to close host fd %d: %v", err)
}
fdnotifier.RemoveFD(int32(e.fd))
e.destroyLocked()
e.mu.Unlock()
})
@@ -380,11 +375,13 @@ func (e *SCMConnectedEndpoint) Release() {
// be called twice because ConnectedEndpoint is both a transport.Receiver and
// transport.ConnectedEndpoint.
func NewSCMEndpoint(ctx context.Context, hostFD int, queue *waiter.Queue, addr string) (*SCMConnectedEndpoint, *syserr.Error) {
e := SCMConnectedEndpoint{ConnectedEndpoint{
fd: hostFD,
addr: addr,
e := SCMConnectedEndpoint{
ConnectedEndpoint: ConnectedEndpoint{
fd: hostFD,
addr: addr,
},
queue: queue,
}}
}
if err := e.init(); err != nil {
return nil, err