Remove unused rpcinet.

PiperOrigin-RevId: 290198756
This commit is contained in:
Adin Scannell
2020-01-16 20:21:09 -08:00
committed by gVisor bot
parent 7a45ae7e67
commit 19b4653147
15 changed files with 2 additions and 2423 deletions
-2
View File
@@ -18,7 +18,6 @@ go_library(
"mounts.go",
"net.go",
"proc.go",
"rpcinet_proc.go",
"stat.go",
"sys.go",
"sys_net.go",
@@ -46,7 +45,6 @@ go_library(
"//pkg/sentry/limits",
"//pkg/sentry/mm",
"//pkg/sentry/socket",
"//pkg/sentry/socket/rpcinet",
"//pkg/sentry/socket/unix",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/usage",
+1 -8
View File
@@ -27,7 +27,6 @@ import (
"gvisor.dev/gvisor/pkg/sentry/fs/proc/seqfile"
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
"gvisor.dev/gvisor/pkg/syserror"
)
@@ -87,15 +86,9 @@ func New(ctx context.Context, msrc *fs.MountSource, cgroupControllers map[string
}
// Add more contents that need proc to be initialized.
p.AddChild(ctx, "net", p.newNetDir(ctx, k, msrc))
p.AddChild(ctx, "sys", p.newSysDir(ctx, msrc))
// If we're using rpcinet we will let it manage /proc/net.
if _, ok := p.k.NetworkStack().(*rpcinet.Stack); ok {
p.AddChild(ctx, "net", newRPCInetProcNet(ctx, msrc))
} else {
p.AddChild(ctx, "net", p.newNetDir(ctx, k, msrc))
}
return newProcInode(ctx, p, msrc, fs.SpecialDirectory, nil), nil
}
-217
View File
@@ -1,217 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proc
import (
"io"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/context"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/waiter"
)
// rpcInetInode implements fs.InodeOperations.
type rpcInetInode struct {
fsutil.SimpleFileInode
// filepath is the full path of this rpcInetInode.
filepath string
k *kernel.Kernel
}
func newRPCInetInode(ctx context.Context, msrc *fs.MountSource, filepath string, mode linux.FileMode) *fs.Inode {
f := &rpcInetInode{
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(mode), linux.PROC_SUPER_MAGIC),
filepath: filepath,
k: kernel.KernelFromContext(ctx),
}
return newProcInode(ctx, f, msrc, fs.SpecialFile, nil)
}
// GetFile implements fs.InodeOperations.GetFile.
func (i *rpcInetInode) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
flags.Pread = true
flags.Pwrite = true
fops := &rpcInetFile{
inode: i,
}
return fs.NewFile(ctx, dirent, flags, fops), nil
}
// rpcInetFile implements fs.FileOperations as RPCs.
type rpcInetFile struct {
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoSplice `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
inode *rpcInetInode
}
// Read implements fs.FileOperations.Read.
//
// This method can panic if an rpcInetInode was created without an rpcinet
// stack.
func (f *rpcInetFile) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
if offset < 0 {
return 0, syserror.EINVAL
}
s, ok := f.inode.k.NetworkStack().(*rpcinet.Stack)
if !ok {
panic("Network stack is not a rpcinet.")
}
contents, se := s.RPCReadFile(f.inode.filepath)
if se != nil || offset >= int64(len(contents)) {
return 0, io.EOF
}
n, err := dst.CopyOut(ctx, contents[offset:])
return int64(n), err
}
// Write implements fs.FileOperations.Write.
//
// This method can panic if an rpcInetInode was created without an rpcInet
// stack.
func (f *rpcInetFile) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
s, ok := f.inode.k.NetworkStack().(*rpcinet.Stack)
if !ok {
panic("Network stack is not a rpcinet.")
}
if src.NumBytes() == 0 {
return 0, nil
}
b := make([]byte, src.NumBytes(), src.NumBytes())
n, err := src.CopyIn(ctx, b)
if err != nil {
return int64(n), err
}
written, se := s.RPCWriteFile(f.inode.filepath, b)
return int64(written), se.ToError()
}
// newRPCInetProcNet will build an inode for /proc/net.
func newRPCInetProcNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
contents := map[string]*fs.Inode{
"arp": newRPCInetInode(ctx, msrc, "/proc/net/arp", 0444),
"dev": newRPCInetInode(ctx, msrc, "/proc/net/dev", 0444),
"if_inet6": newRPCInetInode(ctx, msrc, "/proc/net/if_inet6", 0444),
"ipv6_route": newRPCInetInode(ctx, msrc, "/proc/net/ipv6_route", 0444),
"netlink": newRPCInetInode(ctx, msrc, "/proc/net/netlink", 0444),
"netstat": newRPCInetInode(ctx, msrc, "/proc/net/netstat", 0444),
"packet": newRPCInetInode(ctx, msrc, "/proc/net/packet", 0444),
"protocols": newRPCInetInode(ctx, msrc, "/proc/net/protocols", 0444),
"psched": newRPCInetInode(ctx, msrc, "/proc/net/psched", 0444),
"ptype": newRPCInetInode(ctx, msrc, "/proc/net/ptype", 0444),
"route": newRPCInetInode(ctx, msrc, "/proc/net/route", 0444),
"tcp": newRPCInetInode(ctx, msrc, "/proc/net/tcp", 0444),
"tcp6": newRPCInetInode(ctx, msrc, "/proc/net/tcp6", 0444),
"udp": newRPCInetInode(ctx, msrc, "/proc/net/udp", 0444),
"udp6": newRPCInetInode(ctx, msrc, "/proc/net/udp6", 0444),
}
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
}
// newRPCInetProcSysNet will build an inode for /proc/sys/net.
func newRPCInetProcSysNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
contents := map[string]*fs.Inode{
"ipv4": newRPCInetSysNetIPv4Dir(ctx, msrc),
"core": newRPCInetSysNetCore(ctx, msrc),
}
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
}
// newRPCInetSysNetCore builds the /proc/sys/net/core directory.
func newRPCInetSysNetCore(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
contents := map[string]*fs.Inode{
"default_qdisc": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/default_qdisc", 0444),
"message_burst": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/message_burst", 0444),
"message_cost": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/message_cost", 0444),
"optmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/optmem_max", 0444),
"rmem_default": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/rmem_default", 0444),
"rmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/rmem_max", 0444),
"somaxconn": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/somaxconn", 0444),
"wmem_default": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/wmem_default", 0444),
"wmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/wmem_max", 0444),
}
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
}
// newRPCInetSysNetIPv4Dir builds the /proc/sys/net/ipv4 directory.
func newRPCInetSysNetIPv4Dir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
contents := map[string]*fs.Inode{
"ip_local_port_range": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_local_port_range", 0444),
"ip_local_reserved_ports": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_local_reserved_ports", 0444),
"ipfrag_time": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ipfrag_time", 0444),
"ip_nonlocal_bind": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_nonlocal_bind", 0444),
"ip_no_pmtu_disc": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_no_pmtu_disc", 0444),
"tcp_allowed_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_allowed_congestion_control", 0444),
"tcp_available_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_available_congestion_control", 0444),
"tcp_base_mss": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_base_mss", 0444),
"tcp_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_congestion_control", 0644),
"tcp_dsack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_dsack", 0644),
"tcp_early_retrans": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_early_retrans", 0644),
"tcp_fack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fack", 0644),
"tcp_fastopen": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fastopen", 0644),
"tcp_fastopen_key": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fastopen_key", 0444),
"tcp_fin_timeout": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fin_timeout", 0644),
"tcp_invalid_ratelimit": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_invalid_ratelimit", 0444),
"tcp_keepalive_intvl": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_intvl", 0644),
"tcp_keepalive_probes": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_probes", 0644),
"tcp_keepalive_time": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_time", 0644),
"tcp_mem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_mem", 0444),
"tcp_mtu_probing": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_mtu_probing", 0644),
"tcp_no_metrics_save": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_no_metrics_save", 0444),
"tcp_probe_interval": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_probe_interval", 0444),
"tcp_probe_threshold": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_probe_threshold", 0444),
"tcp_retries1": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_retries1", 0644),
"tcp_retries2": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_retries2", 0644),
"tcp_rfc1337": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_rfc1337", 0444),
"tcp_rmem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_rmem", 0444),
"tcp_sack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_sack", 0644),
"tcp_slow_start_after_idle": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_slow_start_after_idle", 0644),
"tcp_synack_retries": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_synack_retries", 0644),
"tcp_syn_retries": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_syn_retries", 0644),
"tcp_timestamps": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_timestamps", 0644),
"tcp_wmem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_wmem", 0444),
}
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
}
+1 -8
View File
@@ -26,7 +26,6 @@ import (
"gvisor.dev/gvisor/pkg/sentry/fs/proc/seqfile"
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -106,16 +105,10 @@ func (p *proc) newVMDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
func (p *proc) newSysDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
children := map[string]*fs.Inode{
"kernel": p.newKernelDir(ctx, msrc),
"net": p.newSysNetDir(ctx, msrc),
"vm": p.newVMDir(ctx, msrc),
}
// If we're using rpcinet we will let it manage /proc/sys/net.
if _, ok := p.k.NetworkStack().(*rpcinet.Stack); ok {
children["net"] = newRPCInetProcSysNet(ctx, msrc)
} else {
children["net"] = p.newSysNetDir(ctx, msrc)
}
d := ramfs.NewDir(ctx, children, fs.RootOwner, fs.FilePermsFromMode(0555))
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
}
-69
View File
@@ -1,69 +0,0 @@
load("//tools/go_stateify:defs.bzl", "go_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
package(licenses = ["notice"])
go_library(
name = "rpcinet",
srcs = [
"device.go",
"rpcinet.go",
"socket.go",
"stack.go",
"stack_unsafe.go",
],
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet",
visibility = ["//pkg/sentry:internal"],
deps = [
":syscall_rpc_go_proto",
"//pkg/abi/linux",
"//pkg/binary",
"//pkg/sentry/arch",
"//pkg/sentry/context",
"//pkg/sentry/device",
"//pkg/sentry/fs",
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/inet",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/time",
"//pkg/sentry/socket",
"//pkg/sentry/socket/hostinet",
"//pkg/sentry/socket/rpcinet/conn",
"//pkg/sentry/socket/rpcinet/notifier",
"//pkg/sentry/unimpl",
"//pkg/sentry/usermem",
"//pkg/syserr",
"//pkg/syserror",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/stack",
"//pkg/unet",
"//pkg/waiter",
],
)
proto_library(
name = "syscall_rpc_proto",
srcs = ["syscall_rpc.proto"],
visibility = [
"//visibility:public",
],
)
cc_proto_library(
name = "syscall_rpc_cc_proto",
visibility = [
"//visibility:public",
],
deps = [":syscall_rpc_proto"],
)
go_proto_library(
name = "syscall_rpc_go_proto",
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto",
proto = ":syscall_rpc_proto",
visibility = [
"//visibility:public",
],
)
-18
View File
@@ -1,18 +0,0 @@
load("//tools/go_stateify:defs.bzl", "go_library")
package(licenses = ["notice"])
go_library(
name = "conn",
srcs = ["conn.go"],
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn",
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/binary",
"//pkg/sentry/socket/rpcinet:syscall_rpc_go_proto",
"//pkg/sync",
"//pkg/syserr",
"//pkg/unet",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
-187
View File
@@ -1,187 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package conn is an RPC connection to a syscall RPC server.
package conn
import (
"fmt"
"sync/atomic"
"syscall"
"github.com/golang/protobuf/proto"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/unet"
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
)
type request struct {
response []byte
ready chan struct{}
ignoreResult bool
}
// RPCConnection represents a single RPC connection to a syscall gofer.
type RPCConnection struct {
// reqID is the ID of the last request and must be accessed atomically.
reqID uint64
sendMu sync.Mutex
socket *unet.Socket
reqMu sync.Mutex
requests map[uint64]request
}
// NewRPCConnection initializes a RPC connection to a socket gofer.
func NewRPCConnection(s *unet.Socket) *RPCConnection {
conn := &RPCConnection{socket: s, requests: map[uint64]request{}}
go func() { // S/R-FIXME(b/77962828)
var nums [16]byte
for {
for n := 0; n < len(nums); {
nn, err := conn.socket.Read(nums[n:])
if err != nil {
panic(fmt.Sprint("error reading length from socket rpc gofer: ", err))
}
n += nn
}
b := make([]byte, binary.LittleEndian.Uint64(nums[:8]))
id := binary.LittleEndian.Uint64(nums[8:])
for n := 0; n < len(b); {
nn, err := conn.socket.Read(b[n:])
if err != nil {
panic(fmt.Sprint("error reading request from socket rpc gofer: ", err))
}
n += nn
}
conn.reqMu.Lock()
r := conn.requests[id]
if r.ignoreResult {
delete(conn.requests, id)
} else {
r.response = b
conn.requests[id] = r
}
conn.reqMu.Unlock()
close(r.ready)
}
}()
return conn
}
// NewRequest makes a request to the RPC gofer and returns the request ID and a
// channel which will be closed once the request completes.
func (c *RPCConnection) NewRequest(req pb.SyscallRequest, ignoreResult bool) (uint64, chan struct{}) {
b, err := proto.Marshal(&req)
if err != nil {
panic(fmt.Sprint("invalid proto: ", err))
}
id := atomic.AddUint64(&c.reqID, 1)
ch := make(chan struct{})
c.reqMu.Lock()
c.requests[id] = request{ready: ch, ignoreResult: ignoreResult}
c.reqMu.Unlock()
c.sendMu.Lock()
defer c.sendMu.Unlock()
var nums [16]byte
binary.LittleEndian.PutUint64(nums[:8], uint64(len(b)))
binary.LittleEndian.PutUint64(nums[8:], id)
for n := 0; n < len(nums); {
nn, err := c.socket.Write(nums[n:])
if err != nil {
panic(fmt.Sprint("error writing length and ID to socket gofer: ", err))
}
n += nn
}
for n := 0; n < len(b); {
nn, err := c.socket.Write(b[n:])
if err != nil {
panic(fmt.Sprint("error writing request to socket gofer: ", err))
}
n += nn
}
return id, ch
}
// RPCReadFile will execute the ReadFile helper RPC method which avoids the
// common pattern of open(2), read(2), close(2) by doing all three operations
// as a single RPC. It will read the entire file or return EFBIG if the file
// was too large.
func (c *RPCConnection) RPCReadFile(path string) ([]byte, *syserr.Error) {
req := &pb.SyscallRequest_ReadFile{&pb.ReadFileRequest{
Path: path,
}}
id, ch := c.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
<-ch
res := c.Request(id).Result.(*pb.SyscallResponse_ReadFile).ReadFile.Result
if e, ok := res.(*pb.ReadFileResponse_ErrorNumber); ok {
return nil, syserr.FromHost(syscall.Errno(e.ErrorNumber))
}
return res.(*pb.ReadFileResponse_Data).Data, nil
}
// RPCWriteFile will execute the WriteFile helper RPC method which avoids the
// common pattern of open(2), write(2), write(2), close(2) by doing all
// operations as a single RPC.
func (c *RPCConnection) RPCWriteFile(path string, data []byte) (int64, *syserr.Error) {
req := &pb.SyscallRequest_WriteFile{&pb.WriteFileRequest{
Path: path,
Content: data,
}}
id, ch := c.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
<-ch
res := c.Request(id).Result.(*pb.SyscallResponse_WriteFile).WriteFile
if e := res.ErrorNumber; e != 0 {
return int64(res.Written), syserr.FromHost(syscall.Errno(e))
}
return int64(res.Written), nil
}
// Request retrieves the request corresponding to the given request ID.
//
// The channel returned by NewRequest must have been closed before Request can
// be called. This will happen automatically, do not manually close the
// channel.
func (c *RPCConnection) Request(id uint64) pb.SyscallResponse {
c.reqMu.Lock()
r := c.requests[id]
delete(c.requests, id)
c.reqMu.Unlock()
var resp pb.SyscallResponse
if err := proto.Unmarshal(r.response, &resp); err != nil {
panic(fmt.Sprint("invalid proto: ", err))
}
return resp
}
-19
View File
@@ -1,19 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpcinet
import "gvisor.dev/gvisor/pkg/sentry/device"
var socketDevice = device.NewAnonDevice()
-17
View File
@@ -1,17 +0,0 @@
load("//tools/go_stateify:defs.bzl", "go_library")
package(licenses = ["notice"])
go_library(
name = "notifier",
srcs = ["notifier.go"],
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/notifier",
visibility = ["//:sandbox"],
deps = [
"//pkg/sentry/socket/rpcinet:syscall_rpc_go_proto",
"//pkg/sentry/socket/rpcinet/conn",
"//pkg/sync",
"//pkg/waiter",
"@org_golang_x_sys//unix:go_default_library",
],
)
@@ -1,231 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package notifier implements an FD notifier implementation over RPC.
package notifier
import (
"fmt"
"syscall"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn"
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/waiter"
)
type fdInfo struct {
queue *waiter.Queue
waiting bool
}
// Notifier holds all the state necessary to issue notifications when IO events
// occur in the observed FDs.
type Notifier struct {
// rpcConn is the connection that is used for sending RPCs.
rpcConn *conn.RPCConnection
// epFD is the epoll file descriptor used to register for io
// notifications.
epFD uint32
// mu protects fdMap.
mu sync.Mutex
// fdMap maps file descriptors to their notification queues and waiting
// status.
fdMap map[uint32]*fdInfo
}
// NewRPCNotifier creates a new notifier object.
func NewRPCNotifier(cn *conn.RPCConnection) (*Notifier, error) {
id, c := cn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCreate1{&pb.EpollCreate1Request{}}}, false /* ignoreResult */)
<-c
res := cn.Request(id).Result.(*pb.SyscallResponse_EpollCreate1).EpollCreate1.Result
if e, ok := res.(*pb.EpollCreate1Response_ErrorNumber); ok {
return nil, syscall.Errno(e.ErrorNumber)
}
w := &Notifier{
rpcConn: cn,
epFD: res.(*pb.EpollCreate1Response_Fd).Fd,
fdMap: make(map[uint32]*fdInfo),
}
go w.waitAndNotify() // S/R-FIXME(b/77962828)
return w, nil
}
// waitFD waits on mask for fd. The fdMap mutex must be hold.
func (n *Notifier) waitFD(fd uint32, fi *fdInfo, mask waiter.EventMask) error {
if !fi.waiting && mask == 0 {
return nil
}
e := pb.EpollEvent{
Events: mask.ToLinux() | unix.EPOLLET,
Fd: fd,
}
switch {
case !fi.waiting && mask != 0:
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_ADD, Fd: fd, Event: &e}}}, false /* ignoreResult */)
<-c
e := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollCtl).EpollCtl.ErrorNumber
if e != 0 {
return syscall.Errno(e)
}
fi.waiting = true
case fi.waiting && mask == 0:
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_DEL, Fd: fd}}}, false /* ignoreResult */)
<-c
n.rpcConn.Request(id)
fi.waiting = false
case fi.waiting && mask != 0:
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_MOD, Fd: fd, Event: &e}}}, false /* ignoreResult */)
<-c
e := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollCtl).EpollCtl.ErrorNumber
if e != 0 {
return syscall.Errno(e)
}
}
return nil
}
// addFD adds an FD to the list of FDs observed by n.
func (n *Notifier) addFD(fd uint32, queue *waiter.Queue) {
n.mu.Lock()
defer n.mu.Unlock()
// Panic if we're already notifying on this FD.
if _, ok := n.fdMap[fd]; ok {
panic(fmt.Sprintf("File descriptor %d added twice", fd))
}
// We have nothing to wait for at the moment. Just add it to the map.
n.fdMap[fd] = &fdInfo{queue: queue}
}
// updateFD updates the set of events the FD needs to be notified on.
func (n *Notifier) updateFD(fd uint32) error {
n.mu.Lock()
defer n.mu.Unlock()
if fi, ok := n.fdMap[fd]; ok {
return n.waitFD(fd, fi, fi.queue.Events())
}
return nil
}
// RemoveFD removes an FD from the list of FDs observed by n.
func (n *Notifier) removeFD(fd uint32) {
n.mu.Lock()
defer n.mu.Unlock()
// Remove from map, then from epoll object.
n.waitFD(fd, n.fdMap[fd], 0)
delete(n.fdMap, fd)
}
// hasFD returns true if the FD is in the list of observed FDs.
func (n *Notifier) hasFD(fd uint32) bool {
n.mu.Lock()
defer n.mu.Unlock()
_, ok := n.fdMap[fd]
return ok
}
// waitAndNotify loops waiting for io event notifications from the epoll
// object. Once notifications arrive, they are dispatched to the
// registered queue.
func (n *Notifier) waitAndNotify() error {
for {
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollWait{&pb.EpollWaitRequest{Fd: n.epFD, NumEvents: 100, Msec: -1}}}, false /* ignoreResult */)
<-c
res := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollWait).EpollWait.Result
if e, ok := res.(*pb.EpollWaitResponse_ErrorNumber); ok {
err := syscall.Errno(e.ErrorNumber)
// NOTE(magi): I don't think epoll_wait can return EAGAIN but I'm being
// conseratively careful here since exiting the notification thread
// would be really bad.
if err == syscall.EINTR || err == syscall.EAGAIN {
continue
}
return err
}
n.mu.Lock()
for _, e := range res.(*pb.EpollWaitResponse_Events).Events.Events {
if fi, ok := n.fdMap[e.Fd]; ok {
fi.queue.Notify(waiter.EventMaskFromLinux(e.Events))
}
}
n.mu.Unlock()
}
}
// AddFD adds an FD to the list of observed FDs.
func (n *Notifier) AddFD(fd uint32, queue *waiter.Queue) error {
n.addFD(fd, queue)
return nil
}
// UpdateFD updates the set of events the FD needs to be notified on.
func (n *Notifier) UpdateFD(fd uint32) error {
return n.updateFD(fd)
}
// RemoveFD removes an FD from the list of observed FDs.
func (n *Notifier) RemoveFD(fd uint32) {
n.removeFD(fd)
}
// HasFD returns true if the FD is in the list of observed FDs.
//
// This should only be used by tests to assert that FDs are correctly
// registered.
func (n *Notifier) HasFD(fd uint32) bool {
return n.hasFD(fd)
}
// NonBlockingPoll polls the given fd in non-blocking fashion. It is used just
// to query the FD's current state; this method will block on the RPC response
// although the syscall is non-blocking.
func (n *Notifier) NonBlockingPoll(fd uint32, mask waiter.EventMask) waiter.EventMask {
for {
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Poll{&pb.PollRequest{Fd: fd, Events: mask.ToLinux()}}}, false /* ignoreResult */)
<-c
res := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_Poll).Poll.Result
if e, ok := res.(*pb.PollResponse_ErrorNumber); ok {
if syscall.Errno(e.ErrorNumber) == syscall.EINTR {
continue
}
return mask
}
return waiter.EventMaskFromLinux(res.(*pb.PollResponse_Events).Events)
}
}
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package rpcinet implements sockets using an RPC for each syscall.
package rpcinet
File diff suppressed because it is too large Load Diff
-177
View File
@@ -1,177 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpcinet
import (
"fmt"
"syscall"
"gvisor.dev/gvisor/pkg/sentry/inet"
"gvisor.dev/gvisor/pkg/sentry/socket/hostinet"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn"
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/notifier"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/unet"
)
// Stack implements inet.Stack for RPC backed sockets.
type Stack struct {
interfaces map[int32]inet.Interface
interfaceAddrs map[int32][]inet.InterfaceAddr
routes []inet.Route
rpcConn *conn.RPCConnection
notifier *notifier.Notifier
}
// NewStack returns a Stack containing the current state of the host network
// stack.
func NewStack(fd int32) (*Stack, error) {
sock, err := unet.NewSocket(int(fd))
if err != nil {
return nil, err
}
stack := &Stack{
interfaces: make(map[int32]inet.Interface),
interfaceAddrs: make(map[int32][]inet.InterfaceAddr),
rpcConn: conn.NewRPCConnection(sock),
}
var e error
stack.notifier, e = notifier.NewRPCNotifier(stack.rpcConn)
if e != nil {
return nil, e
}
links, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETLINK)
if err != nil {
return nil, fmt.Errorf("RTM_GETLINK failed: %v", err)
}
addrs, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETADDR)
if err != nil {
return nil, fmt.Errorf("RTM_GETADDR failed: %v", err)
}
e = hostinet.ExtractHostInterfaces(links, addrs, stack.interfaces, stack.interfaceAddrs)
if e != nil {
return nil, e
}
routes, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETROUTE)
if err != nil {
return nil, fmt.Errorf("RTM_GETROUTE failed: %v", err)
}
stack.routes, e = hostinet.ExtractHostRoutes(routes)
if e != nil {
return nil, e
}
return stack, nil
}
// RPCReadFile will execute the ReadFile helper RPC method which avoids the
// common pattern of open(2), read(2), close(2) by doing all three operations
// as a single RPC. It will read the entire file or return EFBIG if the file
// was too large.
func (s *Stack) RPCReadFile(path string) ([]byte, *syserr.Error) {
return s.rpcConn.RPCReadFile(path)
}
// RPCWriteFile will execute the WriteFile helper RPC method which avoids the
// common pattern of open(2), write(2), write(2), close(2) by doing all
// operations as a single RPC.
func (s *Stack) RPCWriteFile(path string, data []byte) (int64, *syserr.Error) {
return s.rpcConn.RPCWriteFile(path, data)
}
// Interfaces implements inet.Stack.Interfaces.
func (s *Stack) Interfaces() map[int32]inet.Interface {
interfaces := make(map[int32]inet.Interface)
for k, v := range s.interfaces {
interfaces[k] = v
}
return interfaces
}
// InterfaceAddrs implements inet.Stack.InterfaceAddrs.
func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr {
addrs := make(map[int32][]inet.InterfaceAddr)
for k, v := range s.interfaceAddrs {
addrs[k] = append([]inet.InterfaceAddr(nil), v...)
}
return addrs
}
// SupportsIPv6 implements inet.Stack.SupportsIPv6.
func (s *Stack) SupportsIPv6() bool {
panic("rpcinet handles procfs directly this method should not be called")
}
// TCPReceiveBufferSize implements inet.Stack.TCPReceiveBufferSize.
func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {
panic("rpcinet handles procfs directly this method should not be called")
}
// SetTCPReceiveBufferSize implements inet.Stack.SetTCPReceiveBufferSize.
func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {
panic("rpcinet handles procfs directly this method should not be called")
}
// TCPSendBufferSize implements inet.Stack.TCPSendBufferSize.
func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {
panic("rpcinet handles procfs directly this method should not be called")
}
// SetTCPSendBufferSize implements inet.Stack.SetTCPSendBufferSize.
func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {
panic("rpcinet handles procfs directly this method should not be called")
}
// TCPSACKEnabled implements inet.Stack.TCPSACKEnabled.
func (s *Stack) TCPSACKEnabled() (bool, error) {
panic("rpcinet handles procfs directly this method should not be called")
}
// SetTCPSACKEnabled implements inet.Stack.SetTCPSACKEnabled.
func (s *Stack) SetTCPSACKEnabled(enabled bool) error {
panic("rpcinet handles procfs directly this method should not be called")
}
// Statistics implements inet.Stack.Statistics.
func (s *Stack) Statistics(stat interface{}, arg string) error {
return syserr.ErrEndpointOperation.ToError()
}
// RouteTable implements inet.Stack.RouteTable.
func (s *Stack) RouteTable() []inet.Route {
return append([]inet.Route(nil), s.routes...)
}
// Resume implements inet.Stack.Resume.
func (s *Stack) Resume() {}
// RegisteredEndpoints implements inet.Stack.RegisteredEndpoints.
func (s *Stack) RegisteredEndpoints() []stack.TransportEndpoint { return nil }
// CleanupEndpoints implements inet.Stack.CleanupEndpoints.
func (s *Stack) CleanupEndpoints() []stack.TransportEndpoint { return nil }
// RestoreCleanupEndpoints implements inet.Stack.RestoreCleanupEndpoints.
func (s *Stack) RestoreCleanupEndpoints([]stack.TransportEndpoint) {}
-193
View File
@@ -1,193 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rpcinet
import (
"syscall"
"unsafe"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/syserr"
)
// NewNetlinkRouteRequest builds a netlink message for getting the RIB,
// the routing information base.
func newNetlinkRouteRequest(proto, seq, family int) []byte {
rr := &syscall.NetlinkRouteRequest{}
rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg)
rr.Header.Type = uint16(proto)
rr.Header.Flags = syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST
rr.Header.Seq = uint32(seq)
rr.Data.Family = uint8(family)
return netlinkRRtoWireFormat(rr)
}
func netlinkRRtoWireFormat(rr *syscall.NetlinkRouteRequest) []byte {
b := make([]byte, rr.Header.Len)
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
b[16] = byte(rr.Data.Family)
return b
}
func (s *Stack) getNetlinkFd() (uint32, *syserr.Error) {
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Socket{&pb.SocketRequest{Family: int64(syscall.AF_NETLINK), Type: int64(syscall.SOCK_RAW | syscall.SOCK_NONBLOCK), Protocol: int64(syscall.NETLINK_ROUTE)}}}, false /* ignoreResult */)
<-c
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Socket).Socket.Result
if e, ok := res.(*pb.SocketResponse_ErrorNumber); ok {
return 0, syserr.FromHost(syscall.Errno(e.ErrorNumber))
}
return res.(*pb.SocketResponse_Fd).Fd, nil
}
func (s *Stack) bindNetlinkFd(fd uint32, sockaddr []byte) *syserr.Error {
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Bind{&pb.BindRequest{Fd: fd, Address: sockaddr}}}, false /* ignoreResult */)
<-c
if e := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Bind).Bind.ErrorNumber; e != 0 {
return syserr.FromHost(syscall.Errno(e))
}
return nil
}
func (s *Stack) closeNetlinkFd(fd uint32) {
_, _ = s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Close{&pb.CloseRequest{Fd: fd}}}, true /* ignoreResult */)
}
func (s *Stack) rpcSendMsg(req *pb.SyscallRequest_Sendmsg) (uint32, *syserr.Error) {
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
<-c
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Sendmsg).Sendmsg.Result
if e, ok := res.(*pb.SendmsgResponse_ErrorNumber); ok {
return 0, syserr.FromHost(syscall.Errno(e.ErrorNumber))
}
return res.(*pb.SendmsgResponse_Length).Length, nil
}
func (s *Stack) sendMsg(fd uint32, buf []byte, to []byte, flags int) (int, *syserr.Error) {
// Whitelist flags.
if flags&^(syscall.MSG_DONTWAIT|syscall.MSG_EOR|syscall.MSG_FASTOPEN|syscall.MSG_MORE|syscall.MSG_NOSIGNAL) != 0 {
return 0, syserr.ErrInvalidArgument
}
req := &pb.SyscallRequest_Sendmsg{&pb.SendmsgRequest{
Fd: fd,
Data: buf,
Address: to,
More: flags&linux.MSG_MORE != 0,
EndOfRecord: flags&linux.MSG_EOR != 0,
}}
n, err := s.rpcSendMsg(req)
return int(n), err
}
func (s *Stack) rpcRecvMsg(req *pb.SyscallRequest_Recvmsg) (*pb.RecvmsgResponse_ResultPayload, *syserr.Error) {
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
<-c
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Recvmsg).Recvmsg.Result
if e, ok := res.(*pb.RecvmsgResponse_ErrorNumber); ok {
return nil, syserr.FromHost(syscall.Errno(e.ErrorNumber))
}
return res.(*pb.RecvmsgResponse_Payload).Payload, nil
}
func (s *Stack) recvMsg(fd, l, flags uint32) ([]byte, *syserr.Error) {
req := &pb.SyscallRequest_Recvmsg{&pb.RecvmsgRequest{
Fd: fd,
Length: l,
Sender: false,
Trunc: flags&linux.MSG_TRUNC != 0,
Peek: flags&linux.MSG_PEEK != 0,
}}
res, err := s.rpcRecvMsg(req)
if err != nil {
return nil, err
}
return res.Data, nil
}
func (s *Stack) netlinkRequest(proto, family int) ([]byte, error) {
fd, err := s.getNetlinkFd()
if err != nil {
return nil, err.ToError()
}
defer s.closeNetlinkFd(fd)
lsa := syscall.SockaddrNetlink{Family: syscall.AF_NETLINK}
b := binary.Marshal(nil, usermem.ByteOrder, &lsa)
if err := s.bindNetlinkFd(fd, b); err != nil {
return nil, err.ToError()
}
wb := newNetlinkRouteRequest(proto, 1, family)
_, err = s.sendMsg(fd, wb, b, 0)
if err != nil {
return nil, err.ToError()
}
var tab []byte
done:
for {
rb, err := s.recvMsg(fd, uint32(syscall.Getpagesize()), 0)
nr := len(rb)
if err != nil {
return nil, err.ToError()
}
if nr < syscall.NLMSG_HDRLEN {
return nil, syserr.ErrInvalidArgument.ToError()
}
tab = append(tab, rb...)
msgs, e := syscall.ParseNetlinkMessage(rb)
if e != nil {
return nil, e
}
for _, m := range msgs {
if m.Header.Type == syscall.NLMSG_DONE {
break done
}
if m.Header.Type == syscall.NLMSG_ERROR {
return nil, syserr.ErrInvalidArgument.ToError()
}
}
}
return tab, nil
}
// DoNetlinkRouteRequest returns routing information base, also known as RIB,
// which consists of network facility information, states and parameters.
func (s *Stack) DoNetlinkRouteRequest(req int) ([]syscall.NetlinkMessage, error) {
data, err := s.netlinkRequest(req, syscall.AF_UNSPEC)
if err != nil {
return nil, err
}
return syscall.ParseNetlinkMessage(data)
}
-352
View File
@@ -1,352 +0,0 @@
syntax = "proto3";
// package syscall_rpc is a set of networking related system calls that can be
// forwarded to a socket gofer.
//
package syscall_rpc;
message SendmsgRequest {
uint32 fd = 1;
bytes data = 2 [ctype = CORD];
bytes address = 3;
bool more = 4;
bool end_of_record = 5;
}
message SendmsgResponse {
oneof result {
uint32 error_number = 1;
uint32 length = 2;
}
}
message IOCtlRequest {
uint32 fd = 1;
uint32 cmd = 2;
bytes arg = 3;
}
message IOCtlResponse {
oneof result {
uint32 error_number = 1;
bytes value = 2;
}
}
message RecvmsgRequest {
uint32 fd = 1;
uint32 length = 2;
bool sender = 3;
bool peek = 4;
bool trunc = 5;
uint32 cmsg_length = 6;
}
message OpenRequest {
bytes path = 1;
uint32 flags = 2;
uint32 mode = 3;
}
message OpenResponse {
oneof result {
uint32 error_number = 1;
uint32 fd = 2;
}
}
message ReadRequest {
uint32 fd = 1;
uint32 length = 2;
}
message ReadResponse {
oneof result {
uint32 error_number = 1;
bytes data = 2 [ctype = CORD];
}
}
message ReadFileRequest {
string path = 1;
}
message ReadFileResponse {
oneof result {
uint32 error_number = 1;
bytes data = 2 [ctype = CORD];
}
}
message WriteRequest {
uint32 fd = 1;
bytes data = 2 [ctype = CORD];
}
message WriteResponse {
oneof result {
uint32 error_number = 1;
uint32 length = 2;
}
}
message WriteFileRequest {
string path = 1;
bytes content = 2;
}
message WriteFileResponse {
uint32 error_number = 1;
uint32 written = 2;
}
message AddressResponse {
bytes address = 1;
uint32 length = 2;
}
message RecvmsgResponse {
message ResultPayload {
bytes data = 1 [ctype = CORD];
AddressResponse address = 2;
uint32 length = 3;
bytes cmsg_data = 4;
}
oneof result {
uint32 error_number = 1;
ResultPayload payload = 2;
}
}
message BindRequest {
uint32 fd = 1;
bytes address = 2;
}
message BindResponse {
uint32 error_number = 1;
}
message AcceptRequest {
uint32 fd = 1;
bool peer = 2;
int64 flags = 3;
}
message AcceptResponse {
message ResultPayload {
uint32 fd = 1;
AddressResponse address = 2;
}
oneof result {
uint32 error_number = 1;
ResultPayload payload = 2;
}
}
message ConnectRequest {
uint32 fd = 1;
bytes address = 2;
}
message ConnectResponse {
uint32 error_number = 1;
}
message ListenRequest {
uint32 fd = 1;
int64 backlog = 2;
}
message ListenResponse {
uint32 error_number = 1;
}
message ShutdownRequest {
uint32 fd = 1;
int64 how = 2;
}
message ShutdownResponse {
uint32 error_number = 1;
}
message CloseRequest {
uint32 fd = 1;
}
message CloseResponse {
uint32 error_number = 1;
}
message GetSockOptRequest {
uint32 fd = 1;
int64 level = 2;
int64 name = 3;
uint32 length = 4;
}
message GetSockOptResponse {
oneof result {
uint32 error_number = 1;
bytes opt = 2;
}
}
message SetSockOptRequest {
uint32 fd = 1;
int64 level = 2;
int64 name = 3;
bytes opt = 4;
}
message SetSockOptResponse {
uint32 error_number = 1;
}
message GetSockNameRequest {
uint32 fd = 1;
}
message GetSockNameResponse {
oneof result {
uint32 error_number = 1;
AddressResponse address = 2;
}
}
message GetPeerNameRequest {
uint32 fd = 1;
}
message GetPeerNameResponse {
oneof result {
uint32 error_number = 1;
AddressResponse address = 2;
}
}
message SocketRequest {
int64 family = 1;
int64 type = 2;
int64 protocol = 3;
}
message SocketResponse {
oneof result {
uint32 error_number = 1;
uint32 fd = 2;
}
}
message EpollWaitRequest {
uint32 fd = 1;
uint32 num_events = 2;
sint64 msec = 3;
}
message EpollEvent {
uint32 fd = 1;
uint32 events = 2;
}
message EpollEvents {
repeated EpollEvent events = 1;
}
message EpollWaitResponse {
oneof result {
uint32 error_number = 1;
EpollEvents events = 2;
}
}
message EpollCtlRequest {
uint32 epfd = 1;
int64 op = 2;
uint32 fd = 3;
EpollEvent event = 4;
}
message EpollCtlResponse {
uint32 error_number = 1;
}
message EpollCreate1Request {
int64 flag = 1;
}
message EpollCreate1Response {
oneof result {
uint32 error_number = 1;
uint32 fd = 2;
}
}
message PollRequest {
uint32 fd = 1;
uint32 events = 2;
}
message PollResponse {
oneof result {
uint32 error_number = 1;
uint32 events = 2;
}
}
message SyscallRequest {
oneof args {
SocketRequest socket = 1;
SendmsgRequest sendmsg = 2;
RecvmsgRequest recvmsg = 3;
BindRequest bind = 4;
AcceptRequest accept = 5;
ConnectRequest connect = 6;
ListenRequest listen = 7;
ShutdownRequest shutdown = 8;
CloseRequest close = 9;
GetSockOptRequest get_sock_opt = 10;
SetSockOptRequest set_sock_opt = 11;
GetSockNameRequest get_sock_name = 12;
GetPeerNameRequest get_peer_name = 13;
EpollWaitRequest epoll_wait = 14;
EpollCtlRequest epoll_ctl = 15;
EpollCreate1Request epoll_create1 = 16;
PollRequest poll = 17;
ReadRequest read = 18;
WriteRequest write = 19;
OpenRequest open = 20;
IOCtlRequest ioctl = 21;
WriteFileRequest write_file = 22;
ReadFileRequest read_file = 23;
}
}
message SyscallResponse {
oneof result {
SocketResponse socket = 1;
SendmsgResponse sendmsg = 2;
RecvmsgResponse recvmsg = 3;
BindResponse bind = 4;
AcceptResponse accept = 5;
ConnectResponse connect = 6;
ListenResponse listen = 7;
ShutdownResponse shutdown = 8;
CloseResponse close = 9;
GetSockOptResponse get_sock_opt = 10;
SetSockOptResponse set_sock_opt = 11;
GetSockNameResponse get_sock_name = 12;
GetPeerNameResponse get_peer_name = 13;
EpollWaitResponse epoll_wait = 14;
EpollCtlResponse epoll_ctl = 15;
EpollCreate1Response epoll_create1 = 16;
PollResponse poll = 17;
ReadResponse read = 18;
WriteResponse write = 19;
OpenResponse open = 20;
IOCtlResponse ioctl = 21;
WriteFileResponse write_file = 22;
ReadFileResponse read_file = 23;
}
}